Script 脚本
通过 Script 通知媒介让夜莺以本地进程方式执行 Shell/Python/任意可执行脚本,并通过标准输入(stdin)传入完整告警事件 JSON。
概述
Script(脚本)通知媒介,用于让 n9e 进程在本机执行一个外部脚本(Shell / Python / 任意可执行文件),并把告警事件、消息模板、自定义参数、联系方式等以 JSON 字符串 通过标准输入(stdin)一次性传给脚本。脚本里可以用任意逻辑做下一步处理:写文件、调三方 API、推自建 IM、更新工单……灵活度比 HTTP Callback 还高。
- 适用场景:
- 公司内部接口比较复杂,HTTP body 拼不出来;
- 想在通知前做一次本地逻辑(查 CMDB、按时间段路由、做 dedup);
- 想直接
print调试中间结果。
- 你需要准备:n9e 进程本机的可执行脚本(要么直接把内容贴进表单,要么放在固定路径上)。
- 整个配置分两步:①在夜莺新建 Script 通知媒介,写入脚本内容或路径 → ②在通知规则里选择该媒介。
⚠️ 安全提示:Script 媒介会以 n9e 进程的运行用户 直接执行你写入的代码,相当于远程命令执行的入口。请只把这项能力开放给可信的管理员;不要在脚本里直接拼接事件中的不可信字段,避免命令注入。
脚本运行机制
无论选"使用脚本"还是"使用路径",n9e 在每次触发通知时的执行流程都一样:
- 把当前批次的事件、模板渲染结果、参数、联系方式打包成一个 JSON 对象;
- 启动配置好的脚本进程,JSON 通过 stdin 一次性写入;
- 等待脚本退出,超时未退出则强制 kill;
- 收集 stdout + stderr 的合并输出(最多保留 512 字节,超出截断)作为通知记录里的
details,便于事后排查。
stdin 写入的 JSON 结构(与 Callback 中 $events 一致):
{
"event": { /* events[0] 的快捷引用,单事件场景常用 */ },
"events": [ /* 当前批次的所有事件,结构同 callback */ ],
"tpl": {
"title": "...",
"content": "..."
},
"params": {
"your_custom_key": "your_custom_value"
},
"sendtos": ["13800000000", "alice@example.com"]
}
event/events:完整告警事件对象(字段以models.AlertCurEvent为准);tpl:根据通知规则中"消息模板"渲染后的结果,常见的是tpl.title/tpl.content;params:通知规则里填的自定义参数;sendtos:当媒介绑定了"联系方式"时被注入的目标列表。
第一步:在夜莺新建 Script 通知媒介
-
登录夜莺 → 左侧菜单 通知 → 通知媒介,进入通知媒介列表页。
-
在左侧的媒介类型面板中点击 Script,进入新建页面(对应 URL
/notification-channels/add?ident=script)。
-
表单分两块:基础配置 + 脚本配置。

区块 字段 是否需要改 说明 基础配置 名称 需要 例如 自定义脚本通知,在通知规则里选媒介时看到的就是这个名字基础配置 启用 保持开启 关闭后该媒介不会被发送 变量配置 联系方式 可不填 选择后用户的"手机号/邮箱/钉钉账号"等会以 sendtos数组形式注入 stdin变量配置 参数配置 可加可不加 自定义参数(如 webhook_url、env),通过 stdin 的params字段透传Script 配置 超时时间 一般保持默认 单位毫秒,默认 5000ms(即 5 秒)。脚本超时会被强制 kill Script 配置 脚本类型 需要选 二选一:使用脚本(直接写内容)/ 使用路径(指向已有文件) -
选择 使用脚本 时,下方会出现一个代码编辑器,把你的脚本贴进去:

保存后,n9e 会把脚本写到当前工作目录下的
.notify_script_<媒介ID>文件中(类似.notify_script_25),并chmod 0777,每次执行前会比对内容是否变化、变化时重写。脚本第一行需要包含 shebang,比如
#!/bin/bash、#!/usr/bin/env python3、#!/usr/bin/env -S node等,否则系统不知道用哪个解释器。 -
选择 使用路径 时,填写一个绝对路径,例如
/opt/n9e/etc/scripts/notify.py:这种方式适合脚本逻辑较多、需要版本管理的场景。夜莺不会替你下发文件,你需要自己保证 n9e 进程所在主机上该路径存在、有可执行权限、并能被 n9e 运行用户访问。
-
点击左下角 保存,一条类型为"Script"的通知媒介就建好了。
第二步:在通知规则里使用该媒介
-
左侧菜单 通知 → 通知规则 → 新增(或编辑已有规则)。
-
在"通知配置"区域:

- 通知媒介:选择你刚才创建的 Script 媒介;
- 消息模板:根据脚本里要不要用
tpl.title/tpl.content决定。如果脚本只用events,可任意选; - 自定义参数:如果你在媒介的"变量配置"里加了参数,这里会出现对应输入框;
- 适用级别 / 适用时段 / 适用标签:按需过滤要推送的事件。
-
保存后,点击"通知测试"即可发送一条测试事件到脚本。脚本的 stdout/stderr(截断到 512 字节内)会回写到通知历史里。
脚本示例
下面给出三个最常见的脚本示例,可直接复制使用。
示例 1:Python + requests,按业务标签路由到不同的下游
#!/usr/bin/env python3
import json
import sys
import requests
data = json.load(sys.stdin)
events = data.get("events", [])
if not events:
sys.exit(0)
# 按 tag 路由
ROUTES = {
"team=infra": "https://itsm.example.com/api/n9e/infra",
"team=biz": "https://itsm.example.com/api/n9e/biz",
}
for ev in events:
tags = ev.get("tags_json", {}) or {}
tag_kv = [f"{k}={v}" for k, v in tags.items()]
target = next((url for k, url in ROUTES.items() if k in tag_kv), None)
if not target:
continue
requests.post(target, json=ev, timeout=5)
print("done")
示例 2:把事件写入本地日志,方便回溯
#!/bin/bash
mkdir -p /var/log/n9e-notify
cat >> /var/log/n9e-notify/$(date +%F).log
echo >> /var/log/n9e-notify/$(date +%F).log
之后用
tail -f /var/log/n9e-notify/$(date +%F).log就能实时观察夜莺给脚本投递的内容,调试时非常方便。
常见问题
Q1:脚本没有执行 / 报 permission denied?
A:分别检查:
- 选择"使用路径"时,对应文件必须存在且对 n9e 运行用户具备 执行权限(
chmod +x); - 选择"使用脚本"时,n9e 会自动
chmod 0777,但前提是它对 当前工作目录(一般是 n9e 启动目录)有写权限; - 脚本首行需要正确的 shebang,例如
#!/usr/bin/env python3。
Q2:脚本超时被 kill?
A:默认超时 5000ms,对于要请求外部接口的脚本可能不够。请在 Script 媒介的"超时时间"里把毫秒数调大(例如 30000 即 30 秒)。脚本里也建议自己加 HTTP/请求级超时,避免被外部慢服务拖死。
Q3:脚本里的 stdin 收不到内容?
A:n9e 会关闭 stdin 后再等待退出,所以请在脚本里"读完 stdin 再处理"。Bash 用 payload=$(cat)、Python 用 json.load(sys.stdin) 即可。如果脚本一启动就调用阻塞读取(如 read -t 1),可能错过数据。
Q4:脚本输出哪去了?怎么调试?
A:脚本的 stdout 和 stderr 会被合并保存到通知历史的 details 字段(最多 512 字节)。日常调试可以:
- 在脚本里
echo关键变量; - 同时把 stdin 写到本地日志文件(参考示例 3);
- 也可以在 n9e 的日志里搜索
event_script_notify_result,能看到完整的 stdin、命令行和 stdout。
Q5:能不能在容器里用?
A:可以,但注意:
- 脚本一定要在 n9e 容器内部 存在(写脚本内容的方式会写到容器内的工作目录);
- 如果选"使用路径",需要把脚本所在目录 mount 进容器;
- 容器内可能没有
bash/python3,请安装好或改用静态二进制; - shebang 里的
#!/usr/bin/env xxx需要xxx在PATH里。
Q6:和 Callback 怎么选?
A:
- 下游就是一个 HTTP 接口:直接用 Callback,配置最简单;
- 需要本地处理逻辑(CMDB 查询、按时段判断、调多个下游):用 Script,一切在脚本里搞定;
- 需要把事件存档到本地文件 / 队列:用 Script。
参考资料
- Callback 通用 Webhook(如果只是 POST JSON 到一个 URL,优先用这个)