| AppDynamics | Flashduty | 状态 |
| ----------- | --------- | -- |
| ERROR | Critical | 严重 |
| WARN | Warning | 警告 |
| INFO | Info | 提醒 |
# 蓝鲸智云集成
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/blueking
通过 webhook 的方式同步蓝鲸智云监控事件到 Flashduty On-call,实现告警事件自动化降噪处理
蓝鲸智云到 Flashduty 告警等级映射关系:
| 蓝鲸智云 | Flashduty | 状态 |
| ---- | --------- | -- |
| 致命 | Critical | 严重 |
| 预警 | Warning | 警告 |
| 提醒 | Info | 提醒 |
# Cloudflare 告警事件
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/cloudflare
通过 webhook 的方式同步 Cloudflare 告警事件到 Flashduty On-call,实现告警事件自动化降噪处理
## 一、告警推送配置
1. 登录您的 `Cloudflare` 控制台,转到 `通知` 菜单中,。
2. 在`Webhooks` 中点击创建。
3. 在编辑页面中,名称填写 `Flashduty` ,`URL` 处填写告警集成的推送地址 。
4. 点击 `保存和测试` 完成配置。
配置 Webhook 通道后,即可在通知策略中使用。
## 二、状态对照
当前 Cloudflare 集成推送到 Flashduty 的告警等级均为 Warning,但您可以通过[告警处理 Pipeline](/zh/on-call/integration/alert-integration/alert-pipelines) 来自定义严重程度。
# Dynatrace 告警事件
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/dynatrace
通过 webhook 的方式同步 Dynatrace 告警事件到 Flashduty On-call,实现告警事件自动化降噪处理。
| Dynatrace | Flashduty | 状态 |
| -------------------- | --------- | -- |
| AVAILABILITY | Critical | 严重 |
| ERROR | Warning | 警告 |
| PERFORMANCE | Info | 提醒 |
| RESOURCE\_CONTENTION | Info | 提醒 |
| CUSTOM\_ALERT | Info | 提醒 |
# 观测云告警事件
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/guance
通过 webhook 的方式同步观测云告警事件到 Flashduty On-call,实现告警事件自动化降噪处理
| 观测云 | Flashduty | 状态 |
| ---- | --------- | -- |
| 紧急 | Critical | 严重 |
| 重要 | Warning | 警告 |
| 警告 | Warning | 警告 |
| 信息 | Info | 提醒 |
| 数据断档 | Info | 提醒 |
# Harbor 告警集成
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/harbor
通过 webhook 的方式同步 Harbor 的告警事件到 Flashduty,实现告警事件自动化降噪处理
通过 webhook 的方式同步 Harbor 的告警事件到 Flashduty,实现告警事件自动化降噪处理。
```
{api_host}/push/image/upload?integration_key={integration_key}
```
其中 `{api_host}` 为 Flashduty 的接入域名,公有云默认为 `https://api.flashcat.cloud`,与您的告警推送地址保持一致。
### 请求参数
**Query 参数:**
| 参数 | 必含 | 类型 | 释义 |
| :--------------: | :-: | :----: | :-------------------------------- |
| integration\_key | 是 | string | 集成秘钥,用于确定账户。添加集成后获得,与告警推送共用同一个秘钥。 |
**Form-Data 参数:**
| 参数 | 必含 | 类型 | 释义 |
| :---: | :-: | :--: | :------------------------------------------------- |
| image | 是 | file | 待上传的图片文件,单文件最大 `5MB`。系统根据文件内容(而非扩展名)识别格式,支持的格式见下表。 |
**支持的图片格式:**
| 格式 | Content-Type |
| :--: | :------------------------------------ |
| JPEG | image/jpeg、image/jpg |
| PNG | image/png |
| WebP | image/webp |
| GIF | image/gif |
| TIFF | image/tiff、image/tif |
| BMP | image/bmp |
| ICO | image/x-icon、image/vnd.microsoft.icon |
### 请求响应
| 字段名称 | 必选 | 类型 | 描述 |
| :---------: | :-: | :-------------: | :------------- |
| request\_id | 是 | string | 请求 ID,用于链路追踪 |
| error | 否 | [Error](#Error) | 错误描述,仅当出现错误时返回 |
| data | 否 | [Data](#Data) | 上传结果 |
`。在上报标准告警时填入 `images[].src` 即可引用该图片。 |
Error:
| 字段名称 | 必选 | 类型 | 描述 |
| :-----: | :-: | :----: | :---------------------- |
| code | 是 | string | 错误码,枚举值参考 [Code](#Code) |
| message | 否 | string | 错误描述 |
Code:
| 错误码 | HTTP Status | 描述 |
| :------------------: | :---------: | :--------------------------------- |
| InvalidParameter | 400 | 参数错误,如缺少 image 文件、图片格式不支持或文件超过 5MB |
| Unauthorized | 401 | integration\_key 缺失或无效,或集成、账户已被禁用 |
| RequestTooFrequently | 429 | 请求过于频繁,超过频率限制 |
| InternalError | 500 | 内部或未知错误 |
### 频率限制
为保护服务稳定,图片上传按账户限流:
* 每账户每秒最多 `5` 次;
* 每账户每分钟最多 `50` 次。
超过限制时返回 `RequestTooFrequently`(HTTP 429)。
## 三、请求示例
请求:
```bash theme={null}
curl -X POST '{api_host}/push/image/upload?integration_key={integration_key}' \
-F 'image=@/path/to/screenshot.png'
```
成功响应:
```json theme={null}
{
"request_id": "0ace00116215ab4ca0ec5244b8fc54b0",
"data": {
"image_key": "img_8f3a9c2b1e4d5f6a7b8c9d0e1f2a3b4c"
}
}
```
## 四、在告警中引用图片
拿到 `image_key` 后,在上报 [标准告警](/zh/on-call/integration/alert-integration/alert-sources/standard-alert) 时,将其填入 `images` 数组中某张图片的 `src` 字段即可:
```json theme={null}
{
"event_status": "Warning",
"title_rule": "cpu idle low than 20%",
"labels": {
"service": "engine"
},
"images": [
{
"alt": "CPU 使用率截图",
"src": "img_8f3a9c2b1e4d5f6a7b8c9d0e1f2a3b4c"
}
]
}
```
`images` 与 `image` 结构体的完整字段说明,请参考 [标准告警 - image 结构体](/zh/on-call/integration/alert-integration/alert-sources/standard-alert#image)。
* `image_key` 在 `images[].src` 中的长度限制为 `256` 字符,超长会被丢弃。
* 上传后的图片先临时存储,被告警引用后才会转为长期存储。请在上传后及时将 `image_key` 用于告警上报。
## 五、常见问题
1. **重复上传同一张图片会怎样?**
* 系统按图片内容去重。上传内容完全相同的图片会返回相同的 `image_key`,不会重复占用存储。
2. **可以直接使用图片的公网链接吗?**
* 可以。如果图片已有 `http`/`https` 公网可访问链接,无需上传,直接将链接填入 `images[].src` 即可。图片上传接口仅用于没有公网链接的场景。
3. **image\_key 可以跨账户使用吗?**
* 不可以。`image_key` 与上传时所用 `integration_key` 归属的账户绑定,仅在同一账户内有效。
# 京东云监控集成
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/jdcloud
通过 webhook 的方式同步京东云监控告警事件到 Flashduty On-call,实现告警事件自动化降噪处理
## 在 Flashduty On-call
***
您可通过以下2种方式,获取一个集成推送地址,任选其一即可。
### 使用专属集成
当您不需要将告警事件路由到不同的协作空间,优先选择此方式,更简单。
1. 进入 Flashduty 控制台,选择 **协作空间**,进入某个空间的详情页面
2. 选择 **集成数据** tab,点击 **添加一个集成**,进入添加集成页面
3. 选择 **京东云监控** 集成,点击 **保存**,生成卡片。
4. 点击生成的卡片,可以查看到 **推送地址**,复制备用,完成。
### 使用共享集成
当您需要根据告警事件的 Payload 信息,将告警路由到不同的协作空间,优先选择此方式。
1. 进入 Flashduty 控制台,选择 **集成中心=>告警事件**,进入集成选择页面。
2. 选择 **京东云监控** 集成:
* **集成名称**:为当前集成定义一个名称。
3. 配置默认路由,并选择对应的协作空间(集成创建后可以前往 `路由` 进行更多路由规则的配置)。
4. 点击 **保存** 后,复制当前页面的新生成的 **推送地址** 备用。
5. 完成。
## 在京东云
***
1. 登录京东云控制台,检索 **云监控** 产品,进入对应控制台
2. 在左侧菜单选择 **告警管理 → 通知模版**,创建或编辑通知模版
3. 勾选 **告警回调**,在 `URL` 中输入集成的推送地址
4. 在 `POST` 编辑框中输入以下模版内容:
```json theme={null}
{
"resource_id": "${resourceId}",
"request_id": "${requestId}",
"metric": "${metric}",
"current_value": "${currentValue}",
"times": "${times}",
"tags": "${tags}",
"alert_time": "${alertTime}",
"region": "${region}",
"threshold": "${threshold}",
"service_code": "${serviceCode}",
"as_group_id": "${asGroupId}",
"unhealthy_instance": "${unhealthyInstance}",
"rule_policy_id": "${rulePolicyId}",
"service_code_en": "${serviceCodeEN}",
"service_code_cn": "${serviceCodeCN}",
"level": "${level}",
"resource_name": "${resourceName}",
"ip_address": "${ipAddress}",
"status": "${status}"
}
```
5. 其他选项按需配置,点击 **保存** 完成
1. 在左侧菜单选择 **告警管理 → 全部告警规则**,创建或编辑告警规则
2. 在规则配置页面的 **通知策略** 处,选择 **使用模版** 并选择上一步创建的模版
3. 其他选项按需配置,点击 **保存** 完成
回到 Flashduty 控制台集成列表页面,如果展示了最新事件时间,说明配置成功且收到事件。
## 状态对照
***
京东云监控到 Flashduty 告警等级映射关系:
| 京东云监控 | Flashduty | 状态 |
| :---- | :-------- | :- |
| 紧急 | Critical | 严重 |
| 严重 | Warning | 警告 |
| 一般 | Info | 提醒 |
# 监控宝告警事件
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/jiankongbao
通过 webhook 的方式同步监控宝告警事件到 Flashduty On-call,实现告警事件自动化降噪处理
## 在 Flashduty On-call
***
您可通过以下2种方式,获取一个集成推送地址,任选其一即可。
### 使用专属集成
当您不需要将告警事件路由到不同的协作空间,优先选择此方式,更简单。
1. 进入 Flashduty 控制台,选择 **协作空间**,进入某个空间的详情页面
2. 选择 **集成数据** tab,点击 **添加一个集成**,进入添加集成页面
3. 选择 **监控宝** 集成,点击 **保存**,生成卡片。
4. 点击生成的卡片,可以查看到 **推送地址**,复制备用,完成。
### 使用共享集成
当您需要根据告警事件的 Payload 信息,将告警路由到不同的协作空间,优先选择此方式。
1. 进入 Flashduty 控制台,选择 **集成中心=>告警事件**,进入集成选择页面。
2. 选择 **监控宝** 集成:
* **集成名称**:为当前集成定义一个名称。
3. 配置默认路由,并选择对应的协作空间(集成创建后可以前往 `路由` 进行更多路由规则的配置)。
4. 点击 **保存** 后,复制当前页面的新生成的 **推送地址** 备用。
5. 完成。
## 在监控宝
***
## 一、监控宝告警推送配置
### 步骤1:配置告警通道
1. 登录监控宝控制台。
2. 点击右上方的个人配置。
3. 点击左侧导航栏中的 Webhooks 设置,并点击添加以及选择 URL 回调。
4. 自定义名称输入 Flashduty,回调 URL 输入复制集成的推送地址。
5. 回调方式选择 **POST**,数据格式选择 **JSON**。
6. 勾选**开启 URL 回调**,其他按需选择即可,参考下图配置。
7. 点击保存。
### 步骤2:在监控任务使用 Flashduty 告警通道
1. 创建或编辑已有的监控任务。
2. 此处省略其他告警配置。
3. 在 Webhook 通知处,选择 Flashduty 通道。
4. 保存监控任务即可。
## 二、状态对照
| 监控宝 | Flashduty | 状态 |
| --- | --------- | -- |
| 1 | Warning | 警告 |
| 2 | Info | 提醒 |
# 标签映射 API
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/label-mapping-api
配置标签映射 API,当告警事件到达时,Flashduty 将自动调用您配置的外部 API 获取增强标签,实现告警信息的动态丰富和关联。通过此功能,您可以将 CMDB、HR 系统等外部数据源的信息自动附加到告警上。
## 一、功能概述
标签映射 API 允许您构建自定义的外部服务来增强告警标签。工作流程如下:
1. Flashduty 接收到告警事件
2. 系统根据配置,将事件信息和期望获取的标签列表发送到您的 API
3. 您的 API 查询外部数据源(如 CMDB、数据库等)
4. API 返回计算得到的增强标签
5. Flashduty 将返回的标签附加到告警上
## 二、API 规范
### 请求方式
POST, Content-Type:"application/json"
### 请求 Payload:
| 字段 | 类型 | 必含 | 释义 |
| :-----------------: | :-------------: | :-: | :-------------------------------- |
| result\_label\_keys | \[]string | 是 | 期望返回的标签 Key 列表,由用户在 Flashduty 中配置 |
| event | [Event](#Event) | 是 | 当前告警事件的完整信息 |
**Event**:
| 字段 | 类型 | 必含 | 释义 |
| :----------------: | :----------------: | :-: | :-------------------------------- |
| account\_id | int64 | 是 | 账户 ID |
| channel\_id | int64 | 是 | 协作空间 ID |
| data\_source\_id | int64 | 是 | 数据源 ID |
| data\_source\_type | string | 是 | 数据源类型,如 prometheus、zabbix 等 |
| title | string | 是 | 告警标题 |
| title\_rule | string | 否 | 标题规则 |
| description | string | 否 | 告警描述 |
| alert\_key | string | 是 | 告警唯一标识 |
| alert\_id | string | 是 | 告警 ID |
| event\_severity | string | 是 | 事件严重程度,枚举值:Critical、Warning、Info |
| event\_status | string | 是 | 事件状态,枚举值:Critical、Warning、Info、Ok |
| event\_time | int64 | 是 | 事件时间,Unix 秒时间戳 |
| labels | map\[string]string | 否 | 告警原始标签 KV |
| images | \[]string | 否 | 告警关联图片列表 |
### 请求示例
```json theme={null}
{
"result_label_keys": ["owner_team", "service_tier", "host_ip"],
"event": {
"account_id": 1,
"channel_id": 20,
"data_source_id": 15,
"data_source_type": "prometheus",
"description": "CPU usage for instance '10.0.1.101:9100' is over 95%",
"title": "High CPU Usage on instance 10.0.1.101:9100",
"title_rule": "",
"alert_key": "d41d8cd98f00b204e9800998ecf8427e",
"alert_id": "62d6c0f6b8f1b2b3c4d5e6f7",
"event_severity": "Critical",
"event_status": "Critical",
"event_time": 1678886400,
"labels": {
"region": "us-east-1",
"service": "service-A",
"env": "production",
"instance": "10.0.1.101:9100"
},
"images": []
}
}
```
### 响应规范
**成功响应:**
| 字段 | 类型 | 必含 | 释义 |
| :------------: | :----------------: | :-: | :------------ |
| result\_labels | map\[string]string | 是 | 返回的增强标签 KV 对象 |
* HTTP 状态码:`200 OK`
* 响应体必须是包含 `result_labels` 字段的 JSON 对象
* `result_labels` 的 Key 必须是请求中 `result_label_keys` 指定的标签名
* 如果某个标签无法获取,**不应**在响应中包含该 Key
**成功响应示例:**
```json theme={null}
{
"result_labels": {
"owner_team": "team-database",
"service_tier": "tier-1",
"host_ip": "10.0.1.101"
}
}
```
**失败响应:**
| 状态码 | 含义 |
| :-------------: | :------------------------ |
| 404 Not Found | 根据 event 信息无法找到任何可用于增强的数据 |
| 400 Bad Request | 请求体格式错误或 event 对象缺少关键字段 |
| 5xx | API 内部发生非预期的错误(如数据库连接失败) |
> **提示:** 返回 `200 OK` 状态码 + 空的 `result_labels: {}` 对象也会被视为"无结果",但使用 `404` 状态码是更规范的做法。
## 三、配置映射服务
在 Flashduty 中配置标签映射时,您需要先创建一个映射服务,然后在标签增强规则中引用该服务。
### 映射服务字段说明
| 字段名 | 类型 | 必填 | 释义 |
| :--------------------: | :----------------: | :-: | :------------------------------------------------ |
| api\_name | string | 是 | 服务的可读名称,用于在 UI 中选择和引用,例如 "CMDB 资产查询 API" |
| description | string | 否 | 对该服务的详细描述 |
| url | string | 是 | API 的请求 URL,支持使用模板变量 |
| headers | map\[string]string | 否 | HTTP 请求头,用于传递自定义认证信息,受[安全黑名单](#HeaderBlacklist)限制 |
| timeout | int | 否 | 请求超时时间(单位:秒),可取值:1\~3 |
| retry\_count | int | 否 | 请求失败后的重试次数,可取值:0\~1 |
| insecure\_skip\_verify | bool | 否 | 请求 HTTPS 时跳过证书验证 |
| status | string | 否 | 服务状态,如 enabled、disabled |
### 标签增强规则配置
配置标签增强规则时,只需要关注以下配置:
1. **result\_label\_keys**:指定期望从 API 获取的标签列表,Flashduty 会自动将此列表和当前的 `event` 对象组合成请求体发送给您的 API
2. **映射服务**:选择或配置 API 服务的 URL、Headers 等信息
## 四、Header 安全约束
为了防止安全绕过、请求走私、IP 伪造及缓存污染,在自定义 API 请求头时,**禁止**使用以下 Header。系统网关将自动过滤或拒绝包含这些 Header 的请求。
| 分类 | 禁用 Header | 风险说明 |
| :------------- | :------------------------------------------------------------------------------ | :--------------------------- |
| **认证与授权** | `authorization`, `proxy-authorization`, `cookie`, `x-api-key`, `x-access-token` | 防止凭证泄露或非法劫持已有的认证上下文 |
| **IP 与地理位置伪造** | `x-forwarded-for`, `x-real-ip`, `true-client-ip`, `x-client-ip` | 防止客户端伪造来源 IP 以绕过频率限制或黑白名单 |
| **主机与路由操控** | `host`, `x-forwarded-host`, `x-forwarded-proto`, `x-internal-id`, `x-user-id` | 防止 Host 注入攻击、重定向循环或伪造内部系统 ID |
| **协议与请求走私** | `transfer-encoding`, `upgrade`, `connection` | 防止利用 HTTP 协议差异进行的请求走私攻击 |
### Header 最佳实践
1. **白名单模式**:建议仅允许以 `X-Custom-` 或 `X-Enrich-` 为前缀的自定义 Header
2. **长度限制**:单个 Header 的 Key 或 Value 长度不应超过 1024 字节
3. **格式校验**:Header 的 Value 严禁包含换行符(`\r`、`\n`),以防止 Header 注入攻击
## 五、最佳实践
1. **性能优先:** 此 API 位于告警处理的关键路径上,必须保证低延迟。对外部数据源的查询应尽可能快,建议实现缓存机制。
2. **明确的错误处理:** 善用 HTTP 状态码(特别是 `404`)来传递清晰的执行结果。
3. **幂等性:** API 的设计应尽可能幂等。对于同一个 `event`,多次调用应返回相同的结果。
4. **安全性:** API 必须通过认证和授权机制进行保护,推荐使用自定义 Header(如 `X-Custom-Auth`)传递认证信息。
## 六、常见问题
1. **服务是否有响应超时时间?**
* 服务需要在配置的超时时间内返回响应,超时则认为响应失败
2. **如果 API 返回失败会怎样?**
* 告警会正常处理,但不会附加增强标签
* 根据配置的重试次数,系统可能会重试请求
3. **result\_label\_keys 可以动态变化吗?**
* 是的,您可以在 Flashduty 中随时修改期望获取的标签列表,无需修改 API 代码
# Meraki 告警事件
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/meraki
通过 webhook 的方式同步 Meraki 告警事件到 Flashduty On-call,实现告警事件自动化降噪处理
## 在 Flashduty On-call
***
您可通过以下2种方式,获取一个集成推送地址,任选其一即可。
### 使用专属集成
当您不需要将告警事件路由到不同的协作空间,优先选择此方式,更简单。
1. 进入 Flashduty 控制台,选择 **协作空间**,进入某个空间的详情页面
2. 选择 **集成数据** tab,点击 **添加一个集成**,进入添加集成页面
3. 选择 **Meraki** 集成,点击 **保存**,生成卡片。
4. 点击生成的卡片,可以查看到 **推送地址**,复制备用,完成。
### 使用共享集成
当您需要根据告警事件的 Payload 信息,将告警路由到不同的协作空间,优先选择此方式。
1. 进入 Flashduty 控制台,选择 **集成中心=>告警事件**,进入集成选择页面。
2. 选择 **Meraki** 集成:
* **集成名称**:为当前集成定义一个名称。
3. 配置默认路由,并选择对应的协作空间(集成创建后可以前往 `路由` 进行更多路由规则的配置)。
4. 点击 **保存** 后,复制当前页面的新生成的 **推送地址** 备用。
5. 完成。
## 在 Meraki
***
## 一、Meraki 告警推送配置
1. 登录您的 `Meraki` 控制台,选择需要配置告警的设备。
2. 在 `Alerts` 页面中,按需配置 `Cellular gateway` 和其他部分。
3. 在 `Webhooks` 处,配置 `HTTPS receivers`。
4. `Name` 填写 `Flashduty`,`URL` 填写**告警集成的推送地址**。
5. `Shared secret` 留空,`Payload template` 保持默认的 `Meraki(included)` 即可。
6. 点击 `Save` 保存。
## 二、状态对照
| Meraki | Flashduty | 状态 |
| ------------- | --------- | -- |
| critical | Critical | 严重 |
| warning | Warning | 警告 |
| informational | Info | 提醒 |
# Monit 告警集成
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/monit
Flashduty Monit 告警集成,Monit 服务通过此集成上报告警
当您开通 Monit 服务时,系统会自动为您创建此集成。此集成用于收集 Monit 服务产生的告警事件。
:::tips
您无法修改或删除此集成。但您可以管理集成下的标签增强、告警处理以及路由等规则。
:::
## 如何开启 Monit 告警
前往`Monit`-`告警规则`-`规则详情`页面,配置监控指标和阈值等条件,并开启告警。您可以选择将告警投递至多个协作空间。告警的通知规则遵循协作空间下的分派策略,您可以为团队设定值班人员,在告警发生时分派给值班人。

某些情况下,您可能希望将同一个告警规则产生的告警,按条件路由到不同的协作空间,这个时候您可以选择将告警直接投递到集成,而非协作空间列表。并在当前集成下,设置路由规则。
# Nagios 告警事件
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/nagios
通过 webhook 的方式同步 Nagios 告警事件到 Flashduty,实现告警事件自动化降噪处理
## 在 Flashduty On-call
***
您可通过以下2种方式,获取一个集成推送地址,任选其一即可。
### 使用专属集成
当您不需要将告警事件路由到不同的协作空间,优先选择此方式,更简单。
1. 进入 Flashduty 控制台,选择 **协作空间**,进入某个空间的详情页面
2. 选择 **集成数据** tab,点击 **添加一个集成**,进入添加集成页面
3. 选择 **Nagios** 集成,点击 **保存**,生成卡片。
4. 点击生成的卡片,可以查看到 **推送地址**,复制备用,完成。
### 使用共享集成
当您需要根据告警事件的 Payload 信息,将告警路由到不同的协作空间,优先选择此方式。
1. 进入 Flashduty 控制台,选择 **集成中心=>告警事件**,进入集成选择页面。
2. 选择 **Nagios** 集成:
* **集成名称**:为当前集成定义一个名称。
3. 配置默认路由,并选择对应的协作空间(集成创建后可以前往 `路由` 进行更多路由规则的配置)。
4. 点击 **保存** 后,复制当前页面的新生成的 **推送地址** 备用。
5. 完成。
## 在 Nagios
***
不同的系统和安装方式,Nagios 的安装路径可能不同,请根据实际情况调整以下配置中的路径。
### 一、下载通知脚本
登录 Nagios Server 所在服务器,下载通知脚本到 Nagios 插件目录:
* **Debian/Ubuntu 系统**(通常为 `/usr/lib/nagios/plugins/`):
```bash theme={null}
cd /usr/lib/nagios/plugins/
wget --header="Referer: https://console.flashcat.cloud" https://download.flashcat.cloud/flashduty/integration/nagios/send_to_flashduty.sh
chmod +x send_to_flashduty.sh
```
* **RHEL/CentOS 系统**(通常为 `/usr/lib64/nagios/plugins/`):
```bash theme={null}
cd /usr/lib64/nagios/plugins/
wget --header="Referer: https://console.flashcat.cloud" https://download.flashcat.cloud/flashduty/integration/nagios/send_to_flashduty.sh
chmod +x send_to_flashduty.sh
```
* **源码安装**(通常为 `/usr/local/nagios/libexec/`):
```bash theme={null}
cd /usr/local/nagios/libexec/
wget --header="Referer: https://console.flashcat.cloud" https://download.flashcat.cloud/flashduty/integration/nagios/send_to_flashduty.sh
chmod +x send_to_flashduty.sh
```
脚本中使用了 `curl` 命令,请确保 Nagios Server 上已安装 curl。
### 二、创建 Flashduty 配置文件
下载 Flashduty 配置文件到 Nagios 配置目录:
* **Debian/Ubuntu 系统**(通常为 `/etc/nagios3/conf.d/`):
```bash theme={null}
cd /etc/nagios3/conf.d/
wget --header="Referer: https://console.flashcat.cloud" https://download.flashcat.cloud/flashduty/integration/nagios/flashduty.cfg
```
* **RHEL/CentOS 系统**(通常为 `/etc/nagios/objects/`):
```bash theme={null}
cd /etc/nagios/objects/
wget --header="Referer: https://console.flashcat.cloud" https://download.flashcat.cloud/flashduty/integration/nagios/flashduty.cfg
```
* **源码安装**(通常为 `/usr/local/nagios/etc/objects/`):
```bash theme={null}
cd /usr/local/nagios/etc/objects/
wget --header="Referer: https://console.flashcat.cloud" https://download.flashcat.cloud/flashduty/integration/nagios/flashduty.cfg
```
### 三、修改配置文件
编辑下载的 `flashduty.cfg` 文件,修改以下内容:
1. 将 `pager` 字段的值替换为你在 Flashduty 控制台获取的集成推送地址
2. 根据你的 Nagios 安装路径,修改 `command_line` 中脚本的路径
配置文件内容示例:
```
define contact {
contact_name Flashduty
alias Flashduty Alert Receiver
service_notification_commands notify-service-by-Flashduty
host_notification_commands notify-host-by-Flashduty
service_notification_options w,u,c,r
host_notification_options d,u,r
service_notification_period 24x7
host_notification_period 24x7
pager
}
define command {
command_name notify-host-by-Flashduty
command_line /send_to_flashduty.sh type=HOST WEBHOOK_URL="$CONTACTPAGER$" hostname="$HOSTNAME$" state="$HOSTSTATE$" output="$HOSTOUTPUT$" notification_type="$NOTIFICATIONTYPE$" time="$LONGDATETIME$" host_address="$HOSTADDRESS$" host_alias="$HOSTALIAS$" check_command="$HOSTCHECKCOMMAND$"
}
define command {
command_name notify-service-by-Flashduty
command_line /send_to_flashduty.sh type=SERVICE WEBHOOK_URL="$CONTACTPAGER$" hostname="$HOSTNAME$" state="$SERVICESTATE$" output="$SERVICEOUTPUT$" notification_type="$NOTIFICATIONTYPE$" time="$LONGDATETIME$" host_address="$HOSTADDRESS$" service_desc="$SERVICEDESC$" host_alias="$HOSTALIAS$" max_attempts="$MAXSERVICEATTEMPTS$"
}
```
参数说明:
* `pager`:Flashduty 推送地址,即你在 Flashduty 控制台获取的集成推送地址
* ``:需要替换为实际的脚本路径,如 `/usr/local/nagios/libexec`
* `service_notification_options`:服务告警通知选项,w=警告,u=未知,c=严重,r=恢复
* `host_notification_options`:主机告警通知选项,d=宕机,u=不可达,r=恢复
如需在告警中携带更多信息,可以在 `command_line` 末尾按照 `key=value` 格式追加参数,例如:`environment="production" region="$_HOSTREGION$"`。这些参数将作为标签(labels)推送到 Flashduty。
### 四、引入配置文件
如果你使用的是 **RHEL/CentOS 系统** 或 **源码安装**,需要在 Nagios 主配置文件中引入 Flashduty 配置文件。
* **RHEL/CentOS 系统**:编辑 `/etc/nagios/nagios.cfg`,添加:
```
cfg_file=/etc/nagios/objects/flashduty.cfg
```
* **源码安装**:编辑 `/usr/local/nagios/etc/nagios.cfg`,添加:
```
cfg_file=/usr/local/nagios/etc/objects/flashduty.cfg
```
Debian/Ubuntu 系统通常会自动加载 `/etc/nagios3/conf.d/` 目录下的所有配置文件,无需手动引入。
### 五、将 Flashduty 添加到联系人组
编辑联系人配置文件,将 Flashduty 联系人添加到 `admins` 联系人组(或你使用的其他联系人组):
* **Debian/Ubuntu 系统**:编辑 `/etc/nagios3/conf.d/contacts_nagios2.cfg`
* **RHEL/CentOS 系统**:编辑 `/etc/nagios/objects/contacts.cfg`
* **源码安装**:编辑 `/usr/local/nagios/etc/objects/contacts.cfg`
找到联系人组定义,将 Flashduty 添加到成员列表:
```
define contactgroup {
contactgroup_name admins
alias Nagios Administrators
members nagiosadmin,Flashduty
}
```
### 六、验证配置并重启服务
1. 验证 Nagios 配置文件:
* **Debian/Ubuntu 系统**:
```bash theme={null}
/usr/sbin/nagios3 -v /etc/nagios3/nagios.cfg
```
* **RHEL/CentOS 系统**:
```bash theme={null}
/usr/sbin/nagios -v /etc/nagios/nagios.cfg
```
* **源码安装**:
```bash theme={null}
/usr/local/nagios/bin/nagios -v /usr/local/nagios/etc/nagios.cfg
```
2. 如果验证通过,重启 Nagios 服务:
```bash theme={null}
# Debian/Ubuntu
systemctl restart nagios3
# RHEL/CentOS/源码安装
systemctl restart nagios
```
3. 完成配置后,当 Nagios 检测到告警时,将自动推送到 Flashduty。
## 状态对照
***
Nagios 到 Flashduty 告警等级映射关系:
| Nagios | Flashduty | 状态 |
| ----------- | --------- | -- |
| CRITICAL | Critical | 严重 |
| DOWN | Critical | 严重 |
| UNREACHABLE | Critical | 严重 |
| WARNING | Warning | 警告 |
| OK | Ok | 恢复 |
| UP | Ok | 恢复 |
| UNKNOWN | Info | 提醒 |
# OceanBase 告警事件
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/oceanbase
通过 webhook 的方式同步 OceanBase 告警事件到 Flashduty On-call,实现告警事件自动化降噪处理
## 在 Flashduty On-call
***
您可通过以下2种方式,获取一个集成推送地址,任选其一即可。
### 使用专属集成
当您不需要将告警事件路由到不同的协作空间,优先选择此方式,更简单。
1. 进入 Flashduty 控制台,选择 **协作空间**,进入某个空间的详情页面
2. 选择 **集成数据** tab,点击 **添加一个集成**,进入添加集成页面
3. 选择 **OceanBase** 集成,点击 **保存**,生成卡片。
4. 点击生成的卡片,可以查看到 **推送地址**,复制备用,完成。
### 使用共享集成
当您需要根据告警事件的 Payload 信息,将告警路由到不同的协作空间,优先选择此方式。
1. 进入 Flashduty 控制台,选择 **集成中心=>告警事件**,进入集成选择页面。
2. 选择 **OceanBase** 集成:
* **集成名称**:为当前集成定义一个名称。
3. 配置默认路由,并选择对应的协作空间(集成创建后可以前往 `路由` 进行更多路由规则的配置)。
4. 点击 **保存** 后,复制当前页面的新生成的 **推送地址** 备用。
5. 完成。
## 在 OceanBase
***
## 一、OceanBase告警推送配置
### 步骤1:配置告警通道
1. 登录您的OceanBase控制台,选择告警中心。
2. 进入**告警通道** ,单击**新建通道**按钮,开始新建。
3. 通道类型选择 **自定义脚本** 。
4. 基本配置内容,如下图所示:
5. 配置通道中复制以下脚本内容,同时**请将脚本中的 integration\_key 参数补充上 Flashduty 推送地址中的 integration\_key 值**。
```
#!/usr/bin/env bash
function sendToFlashduty() {
URL="${address}/event/push/alert/standard?integration_key=${integration_key}"
curl -s -X POST ${URL} -H 'Content-Type: application/json' -d '{
"event_status": "'${alert_level}'",
"alert_key": "'${alarm_id}'",
"description": "'"${alarm_description//\"/\\\"}"'",
"title_rule": "$app_types::$name::$alarm_targets",
"event_time":'${timestamp}',
"labels": {
"app_types":"'${app_type}'",
"id":"'${alarm_id}'",
"name":"'${alarm_name}'",
"alarm_level":"'${alarm_level}'",
"alarm_status":"'${alarm_status}'",
"alarm_active_at":"'${alarm_active_at}'",
"alarm_threshold":"'${alarm_threshold}'",
"alarm_type":"'${alarm_type}'",
"alarm_targets":"'${alarm_target}'",
"ob_cluster_group":"'${ob_cluster_group}'",
"ob_cluster":"'${ob_cluster}'",
"hostIP":"'${host_ip}'",
"app_cluster":"'${app_cluster}'",
"alarm_description":"'"${alarm_description//\"/\\\"}"'",
"alarm_url":"'${alarm_url}'"
}
}'
return $?
}
alarm_name=$(echo ${alarm_name} | sed "s/ /_/g")
alarm_target=$(echo ${alarm_target} | sed "s/ /_/g")
#使用告警更新时间作为告警产生时间
timestamp=$(TZ=UTC date -d "${alarm_updated_at}" +%s)
#OceanBase告警通知的状态和级别是中文,所以先转Md5,再做判断
levelMd5=$(echo ${alarm_level} | md5sum | awk '{print$1}')
statusMd5=$(echo ${alarm_status} | md5sum | awk '{print$1}')
#状态Md5
active="048d106318302b41372b4292b5696ad4"
Inactive="bf7da164d431439fe9668fbc964110c4"
#告警级别Md5
down="2e1558b0a152fae2dd15884561b1508d"
critical="59b9b38574ca2ee4f5e264b56f49a83f"
alert="723931b03a5d1cec59eac40cf0703580"
caution="abf4d55ba8926eff32cb44065e634ed3"
info="6aae3f4254789d72aa0cc8ed55b8f11f"
address="https://api.flashcat.cloud"
integration_key=""
#将OceanBase的告警级别定义做转换
if [[ ${statusMd5} == ${Inactive} ]];then
alert_level="Ok"
timestamp=$(TZ=UTC date -d "${alarm_resolved_at}" +%s)
elif [[ ${statusMd5} == "${active}" ]];then
if [[ ${levelMd5} == ${down} || ${levelMd5} == ${critical} ]];then
alert_level="Critical"
elif [[ ${levelMd5} == ${alert} ]];then
alert_level="Warning"
elif [[ ${levelMd5} == ${caution} || ${levelMd5} == ${info} ]];then
alert_level="Info"
fi
fi
#只有状态是告警中或恢复告警才发通知,屏蔽或抑制的不发通知
if [[ ${statusMd5} == ${active} || ${statusMd5} == ${Inactive} ]];then
sendToFlashduty
fi
```
6. Response 校验信息填写 即可。
7. 消息配置中的告警消息格式选择 Markdown。
8. 告警消息模板 **选择简体中文**,并填写以下内容并提交。
```
OCP告警通知-单条告警
- 告警ID: ${alarm_id}
- 名称:${alarm_name}
- 级别:${alarm_level}
- 告警对象:${alarm_target}
- 服务: ${service}
- 概述:${alarm_summary}
- 生成时间:${alarm_active_at}
- 更新时间: ${alarm_updated_at}
- 恢复时间:${alarm_resolved_at}
- 详情:${alarm_description}
- 状态: ${alarm_status}
- 告警类型: ${alarm_type}
- 告警阈值: ${alarm_threshold}
- 集群组: ${ob_cluster_group}
- 集群: ${ob_cluster}
- 主机: ${host_ip}
- 应用集群: ${app_cluster}
- OCP链接:${alarm_url}
```
### 步骤2:配置告警推送
1. 新建推送配置,路径:**告警中心=>告警推送=>新建推送配置**。
2. 推送类型、指定对象按需配置即可。
3. 推送语言选择 **简体中文**。
4. 告警通道选择 **Flashduty** 。
5. 开启 **恢复通知**。
6. 提交。
## 二、状态对照
| OceanBase | Flashduty | 状态 |
| --------- | --------- | -- |
| 停服 | Critical | 严重 |
| 严重 | Warning | 严重 |
| 警告 | Warning | 警告 |
| 注意 | Info | 提醒 |
| 提醒 | Info | 提醒 |
## 状态对照
***
| OceanBase | Flashduty | 状态 |
| --------- | --------- | -- |
| 停服 | Critical | 严重 |
| 严重 | Warning | 严重 |
| 警告 | Warning | 警告 |
| 注意 | Info | 提醒 |
| 提醒 | Info | 提醒 |
# Opmanager 告警事件
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/opmanager
通过 webhook 的方式同步 Opmanager 告警事件到 Flashduty On-call,实现告警事件自动化降噪处理
## 在 Flashduty On-call
***
您可通过以下2种方式,获取一个集成推送地址,任选其一即可。
### 使用专属集成
当您不需要将告警事件路由到不同的协作空间,优先选择此方式,更简单。
1. 进入 Flashduty 控制台,选择 **协作空间**,进入某个空间的详情页面
2. 选择 **集成数据** tab,点击 **添加一个集成**,进入添加集成页面
3. 选择 **OpManager** 集成,点击 **保存**,生成卡片。
4. 点击生成的卡片,可以查看到 **推送地址**,复制备用,完成。
### 使用共享集成
当您需要根据告警事件的 Payload 信息,将告警路由到不同的协作空间,优先选择此方式。
1. 进入 Flashduty 控制台,选择 **集成中心=>告警事件**,进入集成选择页面。
2. 选择 **OpManager** 集成:
* **集成名称**:为当前集成定义一个名称。
3. 配置默认路由,并选择对应的协作空间(集成创建后可以前往 `路由` 进行更多路由规则的配置)。
4. 点击 **保存** 后,复制当前页面的新生成的 **推送地址** 备用。
5. 完成。
## 在 OpManager
***
## 一、OpManager 告警推送配置
1. 登录您的 `OpManager` 控制台,在导航菜单中选择 `Settings => Notification Profiles`。
2. 在 `Notifications` 页面中,点击 `Add` 后选择 `Invoke a Webhook` 添加配置文件。
3. 开始在 Webhook 编辑页面进行配置具体内容。
4. `Hook URL` 中的请求方法选择 `POST`,`URL` 填写**告警集成的推送地址**。
5. `Data Type` 选择 `raw`,`Payload Type` 选择 `JSON`。
6. `Body Content` 填写以下内容:
```
{
"alarmid":"$alarmid",
"message":"$message",
"displayName":"$displayName",
"category":"$category",
"severity":"$stringseverity",
"strModTime":"$strModTime",
"eventType":"$eventType",
"entity":"$entity",
"lastPolledValue":"$lastPolledValue",
"Intf_ifDescr":"$IntfField(ifDescr)",
"Intf_displayName":"$IntfField(displayName)",
"Intf_ifAlias":"$IntfField(ifAlias)",
"Intf_ifName":"$IntfField(ifName)",
"Intf_ipAddress":"$IntfField(ipAddress)",
"Intf_physMedia":"$IntfField(physMedia)",
"Intf_ifIndex(ifIndex)":"$IntfField(ifIndex)",
"Intf_ifCircuitID(ifCircuitID)":"$IntfField(ifCircuitID)",
"Intf_ifSpeedIn(ifSpeedIn)":"$IntfField(ifSpeedIn)",
"Intf_ifSpeedOut(ifSpeedOut)":"$IntfField(ifSpeedOut)",
"Intf_lineID":"$IntfCustomField(Circuit ID)",
"Intf_note":"$IntfCustomField(Comments)",
"Intf_contacts":"$IntfCustomField(Contact Name)",
"Intf_SLA":"$IntfCustomField(SLA)",
"Custom_BuildingNo":"$CustomField(Building)",
"Custom_cabinet":"$CustomField(Cabinet)",
"Custom_note":"$CustomField(Comments)",
"Custom_contacts":"$CustomField(Contact Name)",
"Custom_department":"$CustomField(Department)",
"Custom_RoomNo":"$CustomField(Floor)",
"Custom_serial":"$CustomField(SerialNumbe)",
"Monitor_monitorName":"$MonitorField(monitorName)",
"Monitor_instance":"$MonitorField(instance)",
"Monitor_protocol":"$MonitorField(protocol)",
"Device_type":"$DeviceField(type)",
"Device_ipAddress":"$DeviceField(ipAddress)",
"Device_isSNMP":"$DeviceField(isSNMP)",
"Device_dependent":"$DeviceField(dependent)",
"Device_hardDiskSize":"$DeviceField(hardDiskSize)",
"Device_ramSize":"$DeviceField(ramSize)"
}
```
**特殊说明** :暂不支持添加额外的自定义字段,即使在 Body Content 中引用了自定义字段,也不会生效。
7. `Request Headers` 保持默认的即可。
8. `Time Out` 填写 1-300 之间的任意值,并点击下一步。
9. 在 `Choose the criteria` 配置条件页面中勾选 `Notify when the alarm is cleared`,其他按需配置即可。
10. 选择希望应用此配置文件的设备,使用右箭头将它们移动到选定设备窗口,然后点击下一步。
11. Time Window/Delayed Trigger/Recurring Trigger 可按需配置,然后点击下一步。
12. 为该配置文件添加名称 `Flashduty`,然后点击 `Save` 保存即可完成配置。
## 二、状态对照
| OpManager | Flashduty | 状态 |
| ------------ | --------- | -- |
| Critical | Critical | 严重 |
| Service Down | Critical | 严重 |
| Trouble | Warning | 警告 |
| Attention | Info | 提醒 |
# PagerDuty集成
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/pagerduty
使用兼容 PagerDuty Events API 的协议向 Flashduty On-call 推送告警,实现告警接入与自动降噪。
Flashduty 实现了 PagerDuty Events API,输入和响应完全兼容。因此您可以通过 PagerDuty 协议推送告警事件到 Flashduty On-call,实现告警事件自动化降噪处理。
同样的,对于已经支持推送事件到 PagerDuty 的告警系统(如 ElastAlert),你仅需要修改目的推送地址,即可利用 PagerDuty 协议推送事件到 Flashduty 。
## 在 Flashduty On-call
***
您可通过以下2种方式,获取一个集成推送地址,任选其一即可。
### 使用专属集成
当您不需要将告警事件路由到不同的协作空间,优先选择此方式,更简单。
1. 进入 Flashduty 控制台,选择 **协作空间**,进入某个空间的详情页面
2. 选择 **集成数据** tab,点击 **添加一个集成**,进入添加集成页面
3. 选择 **PagerDuty** 集成,点击 **保存**,生成卡片。
4. 点击生成的卡片,可以查看到 **推送地址**,复制备用,完成。
### 使用共享集成
当您需要根据告警事件的 Payload 信息,将告警路由到不同的协作空间,优先选择此方式。
1. 进入 Flashduty 控制台,选择 **集成中心=>告警事件**,进入集成选择页面。
2. 选择 **PagerDuty** 集成:
* **集成名称**:为当前集成定义一个名称。
3. 配置默认路由,并选择对应的协作空间(集成创建后可以前往 `路由` 进行更多路由规则的配置)。
4. 点击 **保存** 后,复制当前页面的新生成的 **推送地址** 备用。
5. 完成。
## 在 PagerDuty
***
### 请求地址
```
{api_host}/event/push/alert/pagerduty
```
该地址同时支持 PagerDuty V1 和 V2 Events API。**您必须修改 PagerDuty 地址为该地址。**
### Pagerduty V2 Events
#### 参考文档:
[PagerDuty V2 Events](https://developer.pagerduty.com/api-reference/368ae3d938c9e-send-an-event-to-pager-duty)
#### 鉴权方式:
两种方式任选其一:
* 方式 1:在 QueryString 中包含参数 integration\_key
* 方式 2:将 integration\_key 作为 routing\_key 参数传入 Payload
### Pagerduty V1 Events
#### 参考文档:
[PagerDuty V1 Events](https://developer.pagerduty.com/api-reference/f0037990796c8-send-an-event-to-pager-duty)
#### 鉴权方式:
两种方式任选其一:
* 方式 1:在 QueryString 中包含参数 integration\_key
* 方式 2:将 integration\_key 作为 service\_key 参数传入 Payload
### 配置示例
以 [ElastAlert2](https://github.com/jertel/elastalert2) 为例:
1. 步骤 1:获得推送地址
在当前页面填写集成名称并保存,重新打开集成详情,复制推送地址,如:
```
{api_host}/event/push/alert/pagerduty?integration_key=xxx
```
2. 步骤 2:修改推送地址
修改已经部署好的 ElastAlert 实例对应源码,[查看 diff ](https://github.com/jertel/elastalert2/commit/e815a62a6b1eecef6e1fef13afd99d905b67fc34):
3. 步骤 3:上报告警事件
遵循 [ElastAlert PagerDuty 推送配置文档](https://elastalert2.readthedocs.io/en/latest/ruletypes.html#pagerduty) 步骤,配置告警:
```
name: "b"
type: "frequency"
index: "pgy_audit*"
is_enabled: true
num_events: 1
realert:
minutes: 1
terms_size: 50
scan_entire_timeframe: true
timeframe:
minutes: 60
timestamp_field: "created_at"
timestamp_type: "unix_ms"
use_strftime_index: false
alert_subject: "Test {0} 123 aa☃ {1}"
alert_subject_args:
- "account_id"
- "operation"
alert_text: "Test {0} 123 bb☃ {1}"
alert_text_args:
- "request_id"
- "operation_name"
filter:
- query:
query_string:
query: "created_at:*"
# ------- Flashduty ----------------
alert: pagerduty
pagerduty_service_key: xxx
pagerduty_client_name: wahaha
pagerduty_api_version: v2
pagerduty_v2_payload_class: ping failure
pagerduty_v2_payload_component: mysql
pagerduty_v2_payload_group: app-stack
pagerduty_v2_payload_severity: error
pagerduty_v2_payload_source: mysql.host.name
# ------- Flashduty ----------------
```
4. 步骤 4:重启 ElastAlert,等待告警触发
# Sentry 告警事件
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/sentry
通过 webhook 的方式同步 Sentry 告警事件到 Flashduty On-call,实现告警事件自动化降噪处理
## 在 Flashduty On-call
***
您可通过以下2种方式,获取一个集成推送地址,任选其一即可。
### 使用专属集成
当您不需要将告警事件路由到不同的协作空间,优先选择此方式,更简单。
1. 进入 Flashduty 控制台,选择 **协作空间**,进入某个空间的详情页面
2. 选择 **集成数据** tab,点击 **添加一个集成**,进入添加集成页面
3. 选择 **Sentry** 集成,点击 **保存**,生成卡片。
4. 点击生成的卡片,可以查看到 **推送地址**,复制备用,完成。
### 使用共享集成
当您需要根据告警事件的 Payload 信息,将告警路由到不同的协作空间,优先选择此方式。
1. 进入 Flashduty 控制台,选择 **集成中心=>告警事件**,进入集成选择页面。
2. 选择 **Sentry** 集成:
* **集成名称**:为当前集成定义一个名称。
3. 配置默认路由,并选择对应的协作空间(集成创建后可以前往 `路由` 进行更多路由规则的配置)。
4. 点击 **保存** 后,复制当前页面的新生成的 **推送地址** 备用。
5. 完成。
## 在 Sentry
***
## 一、前置说明
Sentry 提供了两类告警机制:Issue Alerts 和 Metric Alerts。Issue Alerts 支持通过 Integrations 中的 WebHooks 实现通知功能,而 Metric Alerts 则限定于使用 Internal Integration 进行告警通知。值得注意的是 Internal Integration 不仅适用于 Metric Alerts,也兼容 Issue Alerts。鉴于 Internal Integration 的广泛适用性,我们决定统一采用这一方式,不再单独依赖 WebHooks,以此来简化告警通知的配置。
## 二、Sentry 告警推送配置
### 步骤1:添加 Flashduty Custom Integrations
1. 登录 Sentry 管理控制台。
2. 在左侧导航栏,找到 **Settings => Custom Integrations**。
3. 点击 Create New Integration 并选择 **Internal Integration**。
4. 在编辑页面。**Name 处填写 Flashduty,WebhookURL 处复制写入集成的推送地址**。
5. 开启 **Alert Rule Action**,参考如下图配置:
5. 在 PERMISSIONS 配置中为 **Issue & Event 配置 Read 权限** 。
6. 在 WEBHOOKS 配置中,勾选 **issue** ,**请不要勾选 error 和 comment**。
7. 配置完成后,点击 Save Changes 完成创建。
**关于 WEBHOOKS 配置的特殊说明:**
1. 勾选 **issue** 后 Flashduty On-call 可以接收 issue 的 resolved 事件,即在 issue 列表中对某个问题进行手动触发 resolved 时,我们会自动恢复 Flashduty On-call 中关联的故障。
2. 不支持 issue 的其他事件,如 create、assigned、archived 和 unresolved。
3. 如果同时勾选了 error 和 comment ,Flashduty 并不会接收和处理这类事件。
### 步骤2:在 Alerts 中使用 Flashduty Integration
1. 在左侧导航栏,找到 **Alerts => Create Alert**。
2. 选择要创建的 Alert 类型,如 Issue 。
3. 触发条件请按需配置。
4. 在 **THEN perform these actions 处 Add action** 并选择 **Send a notification via**。
5. 通知渠道选择上面添加的 **Flashduty**。
6. 配置好其他选项后,点击 **Save Rule** 保存即可。
## 三、状态对照
| Sentry | Flashduty | 状态 |
| --------- | --------- | -- |
| critical | Critical | 严重 |
| warning | Warning | 警告 |
| triggered | Warning | 警告 |
| resolved | Ok | 恢复 |
# SolarWinds 告警事件
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/solarwinds
通过 webhook 的方式同步 SolarWinds 告警事件到 Flashduty On-call,实现告警事件自动化降噪处理
## 在 Flashduty On-call
***
您可通过以下2种方式,获取一个集成推送地址,任选其一即可。
### 使用专属集成
当您不需要将告警事件路由到不同的协作空间,优先选择此方式,更简单。
1. 进入 Flashduty 控制台,选择 **协作空间**,进入某个空间的详情页面
2. 选择 **集成数据** tab,点击 **添加一个集成**,进入添加集成页面
3. 选择 **SolarWinds** 集成,点击 **保存**,生成卡片。
4. 点击生成的卡片,可以查看到 **推送地址**,复制备用,完成。
### 使用共享集成
当您需要根据告警事件的 Payload 信息,将告警路由到不同的协作空间,优先选择此方式。
1. 进入 Flashduty 控制台,选择 **集成中心=>告警事件**,进入集成选择页面。
2. 选择 **SolarWinds** 集成:
* **集成名称**:为当前集成定义一个名称。
3. 配置默认路由,并选择对应的协作空间(集成创建后可以前往 `路由` 进行更多路由规则的配置)。
4. 点击 **保存** 后,复制当前页面的新生成的 **推送地址** 备用。
5. 完成。
## 在 SolarWinds
***
## 一、SolarWinds 告警推送配置
### 步骤1:配置 FlashDudy 告警通道
**前提说明**
1. SolarWinds 的告警类型有五种(Anomaly、Entity、Event、Log、Metric Group),每种类型对应不同的告警通道,所以需要创建五个告警通道,以便在不同告警类型中使用。
2. 在创建 Webhook 通道过程中,其中 Name 字段建议使用: 类型\_Flashduty 组合的形式,例如:Anomaly\_Flashduty。
3. 在选择 **Select Custom Body Template Based On The Alert Types** 时,系统会默认生成相应的 **HTTP POST Body**, **生成的模版内容请不要修改**。
**开始创建**
1. 登录您的 SolarWinds 控制台。
2. 在左侧导航栏找到 `Settings` ,选择 `Notification Services` 并点击 `Webhook` 进入到新建告警通道页面。
3. 点击 `CREATE CONFIGURATION` 进行创建相应的告警通道。
4. 在 `Method` 处选择 **POST** ,`Name` 处可以根据前提说明中的建议进行命名,例如:Anomaly\_Flashduty。
5. `Destination URL` 填写集成的推送地址(当前页面填写集成名称,保存后即可生成地址)。
6. `Content Type` 选择 **application/json**。
7. `Select Custom Body Template Based On The Alert Types` 选择需要创建的类型,例如:Anomaly Based Alert。
8. `HTTP POST Body` 不需要修改,使用系统默认生成的即可。
9. 配置完成后,点击 `CREATE` 保存即可。
10. 如需创建其他类型的 Webhook 通道,重复以上步骤即可。
### 步骤2:在告警策略中使用步骤1创建的告警通道
1. 在左侧导航栏找到 `Alerts`,选择 `Alert Settings`。
2. 创建或编辑已有的策略(告警规则按需配置即可,此处省略告警规则的配置)。
3. 在配置策略页面的 `Actions` 部分中,`Services` 选择 **Webhook** 。
4. `Configuration` 选择步骤1创建的 Anomaly\_Flashduty 通道。
5. `Send an additional notification when the Alert is cleared` 保持开启状态。
6. 其他配置完成后,点击 `Save` 保存即可。
## 二、状态对照
| SolarWinds | Flashduty | 状态 |
| ---------- | --------- | -- |
| Critical | Critical | 严重 |
| Warning | Warning | 警告 |
| Info | Info | 提醒 |
# Splunk 告警事件
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/splunk
通过 webhook 的方式同步 Splunk 告警事件到 Flashduty On-call,实现告警事件自动化降噪处理
## 在 Flashduty On-call
***
您可通过以下2种方式,获取一个集成推送地址,任选其一即可。
### 使用专属集成
当您不需要将告警事件路由到不同的协作空间,优先选择此方式,更简单。
1. 进入 Flashduty 控制台,选择 **协作空间**,进入某个空间的详情页面
2. 选择 **集成数据** tab,点击 **添加一个集成**,进入添加集成页面
3. 选择 **Splunk** 集成,点击 **保存**,生成卡片。
4. 点击生成的卡片,可以查看到 **推送地址**,复制备用,完成。
### 使用共享集成
当您需要根据告警事件的 Payload 信息,将告警路由到不同的协作空间,优先选择此方式。
1. 进入 Flashduty 控制台,选择 **集成中心=>告警事件**,进入集成选择页面。
2. 选择 **Splunk** 集成:
* **集成名称**:为当前集成定义一个名称。
3. 配置默认路由,并选择对应的协作空间(集成创建后可以前往 `路由` 进行更多路由规则的配置)。
4. 点击 **保存** 后,复制当前页面的新生成的 **推送地址** 备用。
5. 完成。
## 在 Splunk
***
## 一、Splunk 告警推送配置
1. 登录您的 Splunk 控制台。
2. 在 `Search adn Report` 应用中,搜索想要监控的关键字,比如 error 关键字。
3. 在右上角的另存为处,选择 `Alerts`,将搜索的关键字配置为监控项。
4. 在弹出的配置框中输入相关信息,`set up` 和 `Triggering conditions` 部分,按实际情况配置。
5. 在 `Trigger Action` 部分,点击 `Add Action` 并选择 `Webhook`。
6. 在 `Webhook` 中的 `URL` 处填写集成的推送地址(当前页面填写集成名称,保存后即可生成地址)并保存,即可完成告警配置。
## 二、状态对照
由于 Splunk 的告警事件没有区分严重程度,所以 Splunk 推送到 Flashduty的所有告警事件状态都为 Warning 且没有恢复事件。
# UCloud CloudWatch 告警集成
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/ucloud-cloudwatch
通过 webhook 的方式同步 UCloud CloudWatch 的告警事件到 Flashduty,实现告警事件自动化降噪处理
通过 webhook 的方式同步 Ucloud CloudWatch 的告警事件到 Flashduty,实现告警事件自动化降噪处理。
## 在 Flashduty
***
### 创建 Ucloud CloudWatch 告警集成
您可通过以下2种方式,获取一个企微机器人告警集成地址,任选其一即可。
#### 使用专属集成
当您不需要将告警事件路由到不同的协作空间,优先选择此方式,更简单。
展开
1. 进入 Flashduty 控制台,选择 **协作空间**,进入某个空间的详情页面
2. 选择 **集成数据** tab,点击 **添加一个集成**,进入添加集成页面
3. 选择 **Ucloud CloudWatch** 集成,点击 **保存**,生成卡片。
4. 点击生成的卡片,可以查看到 **火山引擎 RTC 告警集成地址**,复制备用,完成。
#### 使用共享集成
当您需要根据告警事件的 Payload 信息,将告警路由到不同的协作空间,优先选择此方式。
展开
1. 进入 Flashduty 控制台,选择 **集成中心=>告警事件**,进入集成选择页面。
2. 选择 **Ucloud CloudWatch** 集成:
* **集成名称**:为当前集成定义一个名称。
* **推送模式**:选择企微告警在何种情况下触发或恢复告警。
3. 复制当前页面的 **Ucloud CloudWatch 告警集成地址** 备用。
4. 配置默认路由,并选择对应的协作空间(集成创建后可以前往 `路由` 进行更多路由规则的配置)。
5. 完成。
## 在 Ucloud
***
### 步骤1:配置通知模版
1. 登录您的 Ucloud 控制台,检索 `CloudWatch` 产品,并进入对应产品控制台。
2. 在菜单中选择 `通知管理`,并转到 `通知模版` 页面。
3. 创建或编辑通知模版,在模版页面中勾选 `接口回调`。
4. **回调语言**选择 `英文`,输入框中输入告警集成的推送地址 。
5. 模版名称输入 `Flashduty` 或其他。
6. 其他选项按需配置。
7. 点击 `提交` 完成配置。

### 步骤2:配置告警策略
1. 登录您的 Ucloud 控制台,检索 `CloudWatch` 产品,并进入对应产品控制台。
2. 在菜单中选择 `告警管理`,并转到 `告警策略` 页面。
3. 新建或编辑告警策略,找到策略配置页面的**通知设置**,选择**步骤1** 创建的通知模版。
4. 其他选项按需配置。
5. 点击 `提交` 完成配置。
## 严重程度映射关系
***
当前 Ucloud CloudWatch 告警集成推送到 Flashduty 的严重程度均为 Warning,但您可以通过[告警处理 Pipeline](https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-pipelines) 来自定义严重程度。
# 火山引擎 RTC 告警集成
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/volcengine-rtc
通过 webhook 的方式同步火山引擎 RTC 的告警事件到 Flashduty,实现告警事件自动化降噪处理
通过 webhook 的方式同步火山引擎 RTC 的告警事件到 Flashduty,实现告警事件自动化降噪处理。
## 在 Flashduty
***
### 创建火山引擎 RTC 告警集成
您可通过以下2种方式,获取一个企微机器人告警集成地址,任选其一即可。
#### 使用专属集成
当您不需要将告警事件路由到不同的协作空间,优先选择此方式,更简单。
展开
1. 进入 Flashduty 控制台,选择 **协作空间**,进入某个空间的详情页面
2. 选择 **集成数据** tab,点击 **添加一个集成**,进入添加集成页面
3. 选择 **火山引擎 RTC** 集成,点击 **保存**,生成卡片。
4. 点击生成的卡片,可以查看到 **火山引擎 RTC 告警集成地址**,复制备用,完成。
#### 使用共享集成
当您需要根据告警事件的 Payload 信息,将告警路由到不同的协作空间,优先选择此方式。
展开
1. 进入 Flashduty 控制台,选择 **集成中心=>告警事件**,进入集成选择页面。
2. 选择 **火山引擎 RTC** 集成:
* **集成名称**:为当前集成定义一个名称。
* **推送模式**:选择企微告警在何种情况下触发或恢复告警。
3. 复制当前页面的 **火山引擎 RTC 告警集成地址** 备用。
4. 配置默认路由,并选择对应的协作空间(集成创建后可以前往 `路由` 进行更多路由规则的配置)。
5. 完成。
## 在火山引擎
***
### 配置告警规则
1. 登录您的火山引擎控制台,检索 `实时音视频` 产品,并进入对应产品控制台。
2. 在左侧菜单中选择 `监控台->告警通知`,并转到 `告警规则` 页面。
3. 创建或编辑告警规则,在规则页面中勾选 `告警回调` 并输入告警集成的推送地址 。
4. 其他选项按需配置。
5. 点击 `确定` 完成配置。

## 严重程度映射关系
***
| 火山引擎RTC | Flashduty | 状态 |
| ------- | --------- | -- |
| 严重 | Critical | 严重 |
| 警告 | Warning | 警告 |
| 通知 | Info | 提醒 |
您可以通过[告警处理 Pipeline](/zh/on-call/integration/alert-integration/alert-pipelines) 来自定义严重程度。
# 火山引擎日志服务 TLS 告警事件
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/volcengine-tls
通过 webhook 的方式同步火山引擎日志服务 TLS 告警事件到 Flashduty On-call,实现告警事件自动化降噪处理
## 在 Flashduty On-call
***
您可通过以下2种方式,获取一个集成推送地址,任选其一即可。
### 使用专属集成
当您不需要将告警事件路由到不同的协作空间,优先选择此方式,更简单。
1. 进入 Flashduty 控制台,选择 **协作空间**,进入某个空间的详情页面
2. 选择 **集成数据** tab,点击 **添加一个集成**,进入添加集成页面
3. 选择 **火山引擎 TLS** 集成,点击 **保存**,生成卡片。
4. 点击生成的卡片,可以查看到 **推送地址**,复制备用,完成。
### 使用共享集成
当您需要根据告警事件的 Payload 信息,将告警路由到不同的协作空间,优先选择此方式。
1. 进入 Flashduty 控制台,选择 **集成中心=>告警事件**,进入集成选择页面。
2. 选择 **火山引擎 TLS** 集成:
* **集成名称**:为当前集成定义一个名称。
3. 配置默认路由,并选择对应的协作空间(集成创建后可以前往 `路由` 进行更多路由规则的配置)。
4. 点击 **保存** 后,复制当前页面的新生成的 **推送地址** 备用。
5. 完成。
## 在火山引擎
***
## 一、火山引擎日志服务 TLS 告警推送配置
### 步骤1:创建 Flashduty 告警通道
1. 登录您的火山引擎控制台,检索 `TLS`日志服务产品,并进入对应产品控制台。
2. 在左侧导航栏选择 `日志告警=>通知管理`。
3. 选择 `webhook 告警集成`,并点击 `创建 webhook 告警集成`。
4. 在弹出的编辑框中填写相应的信息,名称填写 `Flashduty`。
5. 类型选择 `自定义 Webhook`,请求方法选择 `POST`。
6. 请求地址填写**集成的推送地址**(当前页面填写集成名称,保存后即可生成地址)。
7. 请求头保持默认的即可,配置完成点击 `创建`。
### 步骤2:创建内容模版
1. 回到 `通知管理` 页面。
2. 选择 `内容模版`,并点击 `创建内容模版`。
3. 在创建模版页面中填写相关信息,模版名称填写 `Flashduty`。
4. 其他类型的通道内容可为空,在 `自定义Webhook` 的通知内容处,填写以下模版内容。
```
{
"AccountID":"{{AccountID}}",
"ProjectName":"{{ProjectName}}",
"AlarmTopicName":"{{AlarmTopicName}}",
"Region":"{{Region}}",
"Alarm":"{{Alarm}}",
"AlarmID":"{{AlarmID}}",
"Duration":"{{Duration}}",
"Condition":"{{Condition}}",
"HappenThreshold":"{{HappenThreshold}}",
"Topics":"{{Topics|join:','}}",
"NotifyTimeUnix":"{{NotifyTimeUnix}}",
"NotifyType":"{{NotifyType}}",
"Severity":"{{Severity}}",
"ConsecutiveAlertNums":"{{ConsecutiveAlertNums}}",
"TriggerParams":{{toJson(TriggerParams)|safe}},
"ExecuteQuery":{{toJson(ExecuteQuery)|safe}},
"DetailUrl":"{{DetailUrl}}",
"FireResultsCount":"{{FireResultsCount}}"
}
```
5. 点击 `确认` 即可完成内容模版的创建。
### 步骤3:创建通知组
1. 回到 `通知管理` 页面。
2. 选择 `通知组`,并点击 `创建通知组`。
3. 在编辑通知组页面中填写相关信息,通知组名称填写 `Flashduty`。
4. 通知规则和其他配置可按需配置(此处略过)。
5. 在通知渠道配置中,接收渠道的 `自定义webhook` 保持勾选状态。
6. `Webhook` 选择**步骤1**创建的 **FlahDuty** 通道。
7. `内容模版` 选择**步骤2**创建的 **FlahDuty** 模版。
8. 其他配置完成后点击 `保存` 即可。
### 步骤4:配置告警策略
1. 在左侧导航栏选择 `日志告警=>告警策略`。
2. 创建或编辑已有的告警策略。
3. 告警规则可按需配置(此处略过)。
4. 在 `通知组` 处,点击 `关联通知组`。
5. 在弹出的选择框中,选择**步骤3**创建的 **Flashduty** 通知组,选择好后,点击 `关联`。
6. 配置好其他内容后,点击 `创建/保存` 即可完成。
## 二、状态对照
| TLS | Flashduty | 状态 |
| --- | --------- | -- |
| 严重 | Critical | 严重 |
| 警告 | Warning | 警告 |
| 通知 | Info | 提醒 |
# zilliz 告警事件
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/zilliz
通过 webhook 的方式同步 zilliz 告警事件到 Flashduty On-call,实现告警事件自动化降噪处理
## 在 Flashduty On-call
***
您可通过以下2种方式,获取一个集成推送地址,任选其一即可。
### 使用专属集成
当您不需要将告警事件路由到不同的协作空间,优先选择此方式,更简单。
1. 进入 Flashduty 控制台,选择 **协作空间**,进入某个空间的详情页面
2. 选择 **集成数据** tab,点击 **添加一个集成**,进入添加集成页面
3. 选择 **zilliz** 集成,点击 **保存**,生成卡片。
4. 点击生成的卡片,可以查看到 **推送地址**,复制备用,完成。
### 使用共享集成
当您需要根据告警事件的 Payload 信息,将告警路由到不同的协作空间,优先选择此方式。
1. 进入 Flashduty 控制台,选择 **集成中心=>告警事件**,进入集成选择页面。
2. 选择 **zilliz** 集成:
* **集成名称**:为当前集成定义一个名称。
3. 配置默认路由,并选择对应的协作空间(集成创建后可以前往 `路由` 进行更多路由规则的配置)。
4. 点击 **保存** 后,复制当前页面的新生成的 **推送地址** 备用。
5. 完成。
## 在 zilliz
***
## 一、告警推送配置
1. 登录您的 `zilliz` 控制台,在 `Project Alerts` 中,创建或修改 `Alert`。
2. 在 `Alert` 编辑页面中的 `Send to` 部分,选择 `Webhook`,Webhook URL 填写告警集成的
推送地址 。
3. 选中 `Alert Resolution Notification`,其他按需选择。
4. 点击 `Save` 或 `Create` 完成配置。
## 二、状态对照
| zilliz | Flashduty | 状态 |
| -------- | --------- | -- |
| CRITICAL | Critical | 严重 |
| WARNING | Warning | 警告 |
# zstack 告警事件
Source: https://docs.flashduty.com/zh/on-call/integration/alert-integration/alert-sources/zstack
通过 webhook 的方式同步 zstack 告警事件到 Flashduty On-call,实现告警事件自动化降噪处理
## 在 Flashduty On-call
***
您可通过以下2种方式,获取一个集成推送地址,任选其一即可。
### 使用专属集成
当您不需要将告警事件路由到不同的协作空间,优先选择此方式,更简单。
1. 进入 Flashduty 控制台,选择 **协作空间**,进入某个空间的详情页面
2. 选择 **集成数据** tab,点击 **添加一个集成**,进入添加集成页面
3. 选择 **ZStack** 集成,点击 **保存**,生成卡片。
4. 点击生成的卡片,可以查看到 **推送地址**,复制备用,完成。
### 使用共享集成
当您需要根据告警事件的 Payload 信息,将告警路由到不同的协作空间,优先选择此方式。
1. 进入 Flashduty 控制台,选择 **集成中心=>告警事件**,进入集成选择页面。
2. 选择 **ZStack** 集成:
* **集成名称**:为当前集成定义一个名称。
3. 配置默认路由,并选择对应的协作空间(集成创建后可以前往 `路由` 进行更多路由规则的配置)。
4. 点击 **保存** 后,复制当前页面的新生成的 **推送地址** 备用。
5. 完成。
## 在 ZStack
***
## 一、告警推送配置
### 步骤1:创建通知对象
1. 登录您的 `ZStack` 控制台,在 `平台运维` 菜单中,找到 `云平台监控`。
2. 点击左侧的 `通知对象`,点击`创建通知对象`或编辑已有的通知对象。
3. 在编辑页面中,名称填写 `Flashduty` ,类型选择 `Webhook`,`地址` 处填写告警集成的
推送地址 。
4. 点击 `发送测试消息`,如果消息发送成功,则说明配置成功。
5. 点击 `确定` 完成配置。
### 步骤2:在告警策略中使用通知对象
1. 登录您的 `ZStack` 控制台,在 `平台运维` 菜单中,找到 `云平台监控`。
2. 点击左侧的 `报警器`,点击`创建资源报警器` 或 `创建事件报警器`,或编辑已有的报警器。
3. 在编辑页面中,`通知对象` 处选择创建的 `Flashduty` 通知对象(资源报警器建议打开恢复通知)。
4. 其他按需配置即可,点击 `确定` 完成配置。
## 二、状态对照
| ZStack | Flashduty | 状态 |
| ------ | --------- | -- |
| 紧急 | Critical | 严重 |
| 严重 | Warning | 警告 |
| 提示 | Info | 信息 |
# 自定义变更事件
Source: https://docs.flashduty.com/zh/on-call/integration/change-integration/custom-event
通过标准协议推送自有系统变更事件到 Flashduty On-call,大部分故障由变更导致,变更和告警事件联动有助于快速定位故障原因
**版本要求**:此功能需要 On-call 标准版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/)
Flashduty On-call 已适配部分常用工单、部署系统的 webhook 协议,对于这些系统您应该首先使用对应的集成。本集成提供了一个标准的 HTTP 接口,需要您开发适配,好处是可以与任何部署系统集成。
## 操作步骤
进入 Flashduty 控制台,选择 **集成中心 => 变更事件**,进入集成选择页面。
选择 **自定义事件** 集成,为当前集成定义一个名称。
点击 **保存** 后,复制当前页面新生成的 **推送地址** 备用。
## 实现协议
### 请求描述
请求方式:
```http theme={null}
POST, Content-Type: application/json
```
请求地址为集成详情页展示的 **推送地址**,格式如下:
```text theme={null}
{api_host}/event/push/change/standard?integration_key={integration_key}
```
### 请求参数
#### Headers
| 字段 | 必含 | 类型 | 说明 |
| :----------- | :-: | :----- | :---------------------- |
| Content-Type | 是 | string | 固定值:`application/json`。 |
#### Query Strings
| 字段 | 必含 | 类型 | 说明 |
| :--------------- | :-: | :----- | :-------------------------- |
| integration\_key | 是 | string | 集成秘钥,用于访问控制。创建集成后可在推送地址中获取。 |
#### Payload
| 字段 | 必含 | 类型 | 说明 |
| :------------- | :-: | :------ | :------------------------------------------------------------------------------------------ |
| title | 是 | string | 变更标题,例如发布单标题、工单标题或部署任务名称。 |
| change\_key | 是 | string | 变更标识。相同 `change_key` 会被识别为同一个变更,后续事件会更新该变更的状态、标签和链接。 |
| change\_status | 是 | string | 变更状态。枚举值(首字母大写):`Planned` 计划中、`Ready` 待执行、`Processing` 执行中、`Canceled` 已取消、`Done` 已完成。 |
| event\_time | 否 | integer | 事件发生时间,Unix 时间戳。支持秒级或毫秒级时间戳;未传时使用 Flashduty 接收事件的时间。 |
| description | 否 | string | 变更描述,例如变更内容、影响范围、执行步骤或回滚方案。 |
| link | 否 | string | 变更详情链接,例如发布单、工单或 CI/CD 任务地址。 |
| labels | 否 | map | 变更标签集合,key 和 value 均为 string 类型。建议 key 遵循 Prometheus 标签命名规范;系统会将 key 中的空格、点号、斜杠等特殊字符替换为下划线。 |
当 `change_status` 为 `Done` 或 `Canceled` 时,Flashduty 会将该事件时间记录为变更结束时间;再次上报非结束状态时,结束时间会被清空。
### 请求响应
| 字段 | 必含 | 类型 | 说明 |
| :---------- | :-: | :-------------- | :-------------- |
| request\_id | 是 | string | 请求 ID,用于链路追踪。 |
| error | 否 | [Error](#error) | 错误描述,仅当出现错误时返回。 |
| data | 否 | object | 上报成功时返回空对象。 |
#### Error
| 字段 | 必含 | 类型 | 说明 |
| :------ | :-: | :----- | :----------------------- |
| code | 是 | string | 错误码,枚举值参考 [Code](#code)。 |
| message | 否 | string | 错误描述。 |
#### Code
| 错误码 | HTTP Status | 说明 |
| :------------------- | :---------: | :----------------------------- |
| InvalidParameter | 400 | 参数错误,例如缺少必填字段、状态枚举值不合法或集成秘钥无效。 |
| InvalidContentType | 400 | `Content-Type` 不支持。 |
| MethodNotAllowed | 405 | HTTP Method 不支持。 |
| Unauthorized | 401 | 登录认证未通过。 |
| AccessDenied | 403 | 权限认证未通过。 |
| RequestTooFrequently | 429 | 请求过于频繁。 |
| RouteNotFound | 404 | 请求 Method 和 Path 未匹配。 |
| ResourceNotFound | 400 | 账户未购买资源,请先前往费用中心下单。 |
| NoLicense | 400 | 账户无充足订阅 License,请先升级或购买订阅。 |
| InternalError | 500 | 内部或未知错误。 |
### 请求示例
请求:
```bash theme={null}
curl -X POST '{api_host}/event/push/change/standard?integration_key={integration_key}' \
-H 'Content-Type: application/json' \
-d '{
"title": "order-service v1.12.0 production release",
"change_key": "deploy-order-service-202607231030",
"change_status": "Processing",
"event_time": 1784773800,
"description": "Deploy order-service v1.12.0 to production cluster cn-shanghai-prod.",
"link": "https://deploy.example.com/releases/deploy-order-service-202607231030",
"labels": {
"service": "order-service",
"env": "prod",
"cluster": "cn-shanghai-prod",
"owner": "sre"
}
}' -v
```
成功响应:
```json theme={null}
{
"request_id": "0ace00116215ab4ca0ec5244b8fc54b0",
"data": {}
}
```
失败响应:
```json theme={null}
{
"request_id": "0ace00116215abc0ba4e52449bd305b0",
"error": {
"code": "InvalidParameter",
"message": "Key: 'ChangeEvent.ChangeStatus' Error:Field validation for 'ChangeStatus' failed on the 'oneof' tag"
}
}
```
## 最佳实践
标签是事件的描述,应尽量丰富标签内容:
* **变更的应用范围**:如 host、cluster 等
* **变更的归属信息**:如 team、owner 等
* **变更的生命周期**:同一个变更在计划、执行、完成或取消时,使用相同 `change_key` 持续上报不同 `change_status`,便于在故障时间线上还原变更过程
## 常见问题
**在 Flashduty On-call 排查**
查看集成是否展示了 **最新事件时间**?如果没有,代表 Flashduty 没有收到推送,请优先排查您的系统。
**在您的系统排查**
1. 确认您请求的地址与集成详情中的地址完全一致
2. 确认您的服务可以访问外网 `api.flashcat.cloud` 域名。如果不可以,您需要为 server 开通外网,或单独针对 Flashduty On-call 的域名开通外网访问
3. 打印 Flashduty 服务的响应结果,查看是否有明确信息
如果以上步骤执行后仍未找到问题根因,请 **携带请求响应中的 request\_id** 联系我们。
# 钉钉
Source: https://docs.flashduty.com/zh/on-call/integration/instant-messaging/dingtalk
通过集成钉钉自建应用,实现在钉钉端内接收和响应告警的能力
**版本要求**:IM 集成需要 On-call 专业版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/)
本文档以钉钉开放平台新版为例。
## AISRE 所需权限
以下为钉钉 IM 集成在开启 AISRE(包含基础通知、作战室、AI SRE 对话和 AI 生成复盘)时需要授予的完整权限清单。进入钉钉开放平台 **权限管理** 页面时,请逐项申请以下官方权限名称。
| 官方权限名称 | 用途 |
| :--------------------------- | :------------------------------------------------- |
| `qyapi_chat_manage` | 获取群聊信息,用于普通通知、酷应用和机器人消息投递 |
| `qyapi_robot_sendmsg` | 发送机器人消息,用于基础通知、会话机器人回复、普通版互动卡片、作战室消息,以及下载机器人接收到的文件 |
| `qyapi_chat_read` | 读取群聊信息,用于作战室群状态确认和群成员处理 |
| `qyapi_chat_base_read` | 读取群聊基础信息,用于作战室群查询 |
| `qyapi_get_member_by_mobile` | 根据手机号获取钉钉用户 ID,用于一键关联用户和邀请成员进入作战室 |
| `Card.Instance.Write` | 创建并投放 AI SRE 流式卡片;仅在启用钉钉 AI 流式卡片模板时需要 |
| `Card.Streaming.Write` | 更新 AI SRE 流式卡片内容;仅在启用钉钉 AI 流式卡片模板时需要 |
如果未配置钉钉 AI 流式卡片模板,AI SRE 会降级使用普通版互动卡片或会话机器人消息回复,此时仍需要保留 `qyapi_robot_sendmsg`。
## 一、创建钉钉应用与添加钉钉集成
### 1. 创建自建应用
访问 [钉钉开发者后台](https://open-dev.dingtalk.com/fe/app) → 应用开发 → **企业内部开发**,创建应用。
详见钉钉开发文档 [创建企业内部应用-H5 微应用](https://open.dingtalk.com/document/orgapp/microapplication-creation-and-release-process#title-ovn-666-1ty)。

应用图标可使用 [Flashduty 官方 icon](https://flashduty-public.oss-cn-beijing.aliyuncs.com/icons/flashduty-20251216.png)。
### 2. 复制企业 `CorpId`
点击页面右上角企业头像,在下拉菜单中复制 `CorpId`。

回到 Flashduty On-call 集成配置页面,在表单中填入对应的 `CorpId`。
### 3. 复制应用凭证信息
进入创建的应用详情界面,通过左侧菜单栏前往 应用能力 → **凭证与基础信息** 页面,复制 `AgentId`、`Client ID` 和 `Client Secret`。

回到 Flashduty On-call 集成配置页面,在表单中填入对应的 `AgentId`、 `Client ID` 和 `Client Secret`。
### 4. 复制事件订阅信息
前往 开发配置 → **事件与回调** 页面。设置推送方式为 `HTTP推送`,然后点击按钮生成 `加密 aes_key` 和 `签名 Token`,并复制保存。

回到 Flashduty On-call 集成配置页面,在表单中填入对应的 `加密 aes_key` 和 `签名 Token`,点击 **保存** 按钮。
### 5. 配置事件订阅
进入 开发配置 → **事件订阅** 页面。
根据 Flashduty 集成详情中的 `事件订阅请求地址`,配置 **事件订阅请求网址**。配置完成后 **保存**。

在 **保存** 按钮下方,选中 `群会话更换群名称`、`群内安装酷应用` 和 `群内卸载酷应用` 三种群会话事件,配置完成后点击 **保存**。

### 6. 添加应用能力
创建酷应用。进入 开发配置 → 添加应用能力 → 酷应用 → **酷应用列表** 页面,点击 **创建酷应用** 按钮,选择 **扩展到群会话**。
进入 **编辑酷应用** 页面,完成以下步骤:
1. 填写基本信息。图标可使用 [Flashduty 官方 icon](https://flashduty-public.oss-cn-beijing.aliyuncs.com/icons/flashduty-20251216.png)。

2. 配置功能设计。在左侧选中 **群快捷入口** 和 **消息卡片**。群快捷入口图标可使用 [Flashduty 官方 icon](https://flashduty-public.oss-cn-beijing.aliyuncs.com/icons/flashduty-20251216.png),桌面和移动端访问地址请复制集成详情里的 **酷应用网页地址**。

3. 跳过第三步功能开发,进入第四步 **预览发布**,点击 **发布** 按钮并确认。
### 7. 配置机器人与消息推送
进入 应用能力 → **机器人** 页面,打开机器人配置,填写名称并上传图标,然后点击 **保存**。图标可使用 [Flashduty 官方 icon](https://flashduty-public.oss-cn-beijing.aliyuncs.com/icons/flashduty-20251216.png)。

### 8. 配置应用地址
进入 应用能力 → **网页应用** 页面。
根据 Flashduty 集成详情中的 `应用首页地址` 和 `PC 端首页地址`,配置 **应用首页地址** 和 **PC 端首页地址**。完成后点击 **保存**。

### 9. 申请应用权限
进入 开发配置 → **权限管理** 页面,为先前步骤创建的群应用申请以下权限:
* `qyapi_chat_manage`:获取群聊信息
* `qyapi_robot_sendmsg`:向群聊或个人发送消息
如果需要开启 AISRE,请同时确认页面开头的 [AISRE 所需权限](#aisre-permissions) 已全部申请。

如果需要继续配置作战室,请先发布一次自建应用。应用发布后,才能在场景群的 **可选应用** 列表中选择该应用。发布路径请参考 [应用发布与使用](#publish)。
## 二、配置作战室
若您无需配置作战室功能,可跳过本步骤,直接进入 [**应用发布与使用**](#publish)。
> 配置作战室前,请确认应用已获得页面开头列出的 [AISRE 所需权限](#aisre-permissions)。
### 1. 申请应用权限
进入 开发配置 → **权限管理** 页面,为先前步骤创建的群应用申请以下权限:
* `qyapi_chat_read`:获取群聊信息
* `qyapi_chat_base_read`:获取群聊信息
* `qyapi_get_member_by_mobile`:允许当前应用根据手机号获取钉钉用户以便邀请用户加入群聊

### 2. 配置群模板
通过钉钉开放平台顶部菜单栏,前往 开放能力 → **场景群**。
1. 配置 **群机器人**。在左侧菜单栏中选择 **机器人**,然后点击 **创建群机器人**。
本步骤中配置的 **群机器人** 和 **应用机器人** 是两个不同的概念。群机器人被用于在生成群聊时自动创建群机器人。群机器人和应用机器人拥有不同的 **机器人 ID**。若要为钉钉开启作战室功能,必须额外配置 **群机器人**。
填写群机器人配置。若需要使用 AISRE,请按下表配置 **消息回调地址**、**消息回调 token** 和 **信息来源网站**。这三项用于 AISRE 的钉钉消息回调。
钉钉当前对消息回调地址的证书校验不兼容 `api.flashcat.cloud` 使用的 ACME 自动签发证书。为保证钉钉能够正常校验并回调消息,请将 Flashduty 集成配置页提供的消息地址中的域名替换为 `dingtalk-message.flashcat.cloud`。
**示例配置**:
| **配置项** | **值** |
| ---------- | ------------------------------------------------------------------------------------------------------ |
| 机器人名称 | Flashduty |
| 机器人头像 | [Flashduty 官方 icon](https://flashduty-public.oss-cn-beijing.aliyuncs.com/icons/flashduty-20251216.png) |
| 简介 | Flashduty |
| 消息预览图 | [Flashduty 官方 icon](https://flashduty-public.oss-cn-beijing.aliyuncs.com/icons/flashduty-20251216.png) |
| 详细描述 | Flashduty 消息推送机器人。 |
| 消息回调地址 | Flashduty 集成配置页提供的消息地址,并将域名 `api.flashcat.cloud` 替换为 `dingtalk-message.flashcat.cloud` |
| 消息回调 token | 步骤 4 在 开发配置 → **事件与回调** 中生成的 `签名 Token` |
| 信息来源网站 | `https://www.flashduty.com` |
完成配置后,点击 **创建**,然后点击 **审批**。右上角弹出 “提交成功” 后,钉钉已自动完成群机器人的审批。

2. 配置 **群模板**。在左侧菜单栏中选择 **群模板**,点击 **创建群模板**。
将 **企业类型** 设置为 `企业内部`,将 **可选应用** 设置为先前步骤中已发布的自建应用。然后,在下一步骤中填写模板信息。
**模板名称**、**图标**、**描述**、**文案介绍**、**模板描述**、**图片介绍** 等介绍性信息不会影响群模板功能的使用,您可选择任意满足要求的值进行配置。
**示例配置**:
| **配置项** | **值** |
| ------- | ------------------------------------------------------------------------------------------------------ |
| 模板名称 | Flashduty 作战室 |
| 图标 | [Flashduty 官方 icon](https://flashduty-public.oss-cn-beijing.aliyuncs.com/icons/flashduty-20251216.png) |
| 描述 | 为活跃故障一键创建作战室。 |
| 文案介绍 | 为活跃故障一键创建作战室。 |
| 模板描述 | 为活跃故障一键创建作战室。 |
| 图片介绍 | [Flashduty 官方 icon](https://flashduty-public.oss-cn-beijing.aliyuncs.com/icons/flashduty-20251216.png) |
在 **选择机器人** 配置项中,点击 **选择已创建的机器人**,选择上一步骤中创建的群机器人。其他配置项保持默认。最后点击 **保存编辑**。


在 **填写灰度群** 步骤中,点击 **创建灰度群**,然后点击 **发布灰度**。
最后,再次点击左侧菜单栏的 **群模板**,然后点击进入刚才创建的群模板。点击 **提交审核**,待钉钉自动通过审核后,最后点击 **发布**。
3. 在已经发布的群模板详细信息页,复制 **模板 ID** 和 **机器人 ID**。

回到 Flashduty On-call 集成配置页面,在表单中填入对应的 `模版 ID` 和 `机器人 ID`,点击 **保存** 按钮。
同一时间仅支持在一个 IM 集成中开启作战室功能。如果你已在其他 IM 集成(如飞书、Slack、企业微信)中启用了作战室,需要先在该集成中关闭后,才能在当前钉钉集成中开启。
### AI SRE 控制项
开启 **作战室** 后,配置页会显示以下 AI SRE 控制项,默认均为开启:
* **自动发起 AI 故障分析**:作战室创建成功后,自动发起一次 AI 故障分析。
* **允许群聊 @ AI SRE**:允许在此集成已接入的群聊中 @ AI SRE 发起对话;关闭后不会响应该入口。
如果账户尚未启用 AI SRE,以上配置暂不生效。
## 三、应用发布与使用
完成上述步骤后,请确认自建应用已发布最新版本。若尚未发布,或发布后又调整了应用配置,请前往 应用发布 → **版本管理与发布**,创建新版本并发布。
为了确保所有人可以使用应用,需将应用 **可见范围** 调整为全部员工,再进行应用发布。

应用发布后,即可通过 **手机端** 或 **PC 端** 访问应用。首次访问需要登录并关联钉钉与 Flashduty 账号,后续可以免登录使用。
钉钉 → 工作台 → 搜索应用名称 → **打开应用**
钉钉 → 工作台 → 搜索应用名称 → **打开应用**
## 四、关联用户
在集成详情页的 **关联用户** 页签中,你可以查看团队成员与钉钉账号的关联状态,并快速完成批量关联。
### 查看关联状态
关联用户列表展示所有团队成员及其关联状态。你可以通过以下方式筛选:
| 筛选项 | 说明 |
| :------ | :-------------- |
| **全部** | 查看所有团队成员 |
| **已关联** | 仅查看已完成钉钉账号关联的成员 |
| **未关联** | 仅查看尚未关联钉钉账号的成员 |
支持通过名称或邮箱搜索成员。
### 一键关联
当存在未关联的成员时,可以点击 **一键关联** 按钮。系统将尝试通过手机号换取钉钉开放平台的账号 ID 并自动关联,效果等同于成员使用相同手机号在钉钉平台登录 Flashduty。
成员完成关联后,系统才能向其推送钉钉消息通知。如果关联失败,请确认成员的手机号是否与钉钉账号一致。
## 五、常见问题
前往 钉钉 → 工作台 → 搜索应用名称 → **打开应用**,完成一次登录以关联钉钉与 Flashduty 账号,系统才能获取用户身份并推送消息。
* 前往 钉钉 → 工作台 → 搜索应用名称 → **打开应用**,完成一次登录以关联钉钉与 Flashduty 账号。如果已经登录过,尝试点击右上角菜单,切换账户,重新登录来绑定账号
* 确保您已购买足够的 License。已使用 License 情况,可以在 控制台 → [**费用中心**](https://console.flashcat.cloud/wallet) 查看
1. 前往钉钉,选择群聊会话安装酷应用,否则无法获取群聊列表


2. 回到分派策略配置页面,刷新后重新选择群聊列表
3. 如果仍然无法获取群聊列表,请尝试在群内卸载酷应用后,重试以上步骤。如果问题依旧,请联系客户或专属技术支持
* 请再次检查是否为应用配置了作战室功能[所需权限](#war-room-scope)
* 请参考 [作战室介绍文档](/zh/on-call/advanced/war-room) 的 **常见问题** 部分
| **钉钉版本** | **调用总量/月** | **QPS** | **刷新时间** |
| :------: | :--------: | :-----: | :------: |
| 标准版 | 10,000 次 | 20 | 每月 1 日 |
| 专业版 | 50 万次 | 40 | 每月 1 日 |
| 专属版 | 550 万次 | 60 | 每月 1 日 |
超出 API 调用量限制后,钉钉应用将无法正常推送消息。建议合理使用通知渠道。详见 [钉钉官方文档](https://open.dingtalk.com/document/orgapp/descriptions-about-adjusting-limit-and-frequency-of-api-calls?spm=ding_open_doc.document.0.0.6f6b21d9WtkxJI)。
# 飞书/Lark
Source: https://docs.flashduty.com/zh/on-call/integration/instant-messaging/lark
通过集成飞书自建应用,您可以在飞书端内接收和响应告警
**版本要求**:IM 集成需要 On-call 专业版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/)
## AISRE 所需权限
以下为飞书/Lark IM 集成在开启 AISRE(包含基础通知、作战室、AI SRE 对话和 AI 生成复盘)时需要授予的完整权限清单。进入飞书/Lark 开放平台 **权限管理** 页面时,请逐项申请以下官方权限名称。
| 官方权限名称 | 用途 |
| :--------------------------------- | :------------------------------------ |
| `im:chat` | 创建和管理作战室群、获取群信息、添加群成员 |
| `im:message` | 读取和发送单聊、群组消息 |
| `im:message.p2p_msg:readonly` | 接收用户发给机器人的单聊消息;缺少该权限时,AI SRE 无法收到单聊提问 |
| `im:message.group_at_msg:readonly` | 接收群聊中 @ 机器人的消息;群聊 AI SRE 对话需要该权限 |
| `im:message:send_as_bot` | 以机器人身份发送 AI SRE 回复和作战室消息 |
| `im:message:update` | 更新应用已发送的消息,用于 AI SRE 流式回复更新 |
| `im:message.group_msg` | 读取群聊历史消息;AI SRE 上下文和 AI 生成复盘报告需要该权限 |
| `im:message.reactions:read` | 查询消息表情反应,用于 AI SRE 处理状态确认 |
| `im:message.reactions:write_only` | 添加或删除消息表情反应,用于 AI SRE 处理状态确认 |
| `im:resource` | 上传和下载消息中的图片、文件等资源 |
| `cardkit:card:write` | 创建和更新 CardKit 卡片,用于 AI SRE 流式回复 |
| `contact:user.id:readonly` | 通过手机号或邮箱获取用户 ID,用于自动关联和邀请成员 |
| `contact:contact.base:readonly` | 获取通讯录基本信息,用于读取用户和部门基础资料 |
| `contact:user.base:readonly` | 获取用户基础信息,用于显示发送者名称 |
## 一、创建飞书应用
***
### 1. 创建自建应用
访问 [飞书开发者后台](https://open.feishu.cn/app),创建企业内自建应用。应用图标可使用 [Flashduty 官方 icon](https://flashduty-public.oss-cn-beijing.aliyuncs.com/icons/flashduty-20251216.png)。
详见飞书开发文档 [创建企业自建应用](https://open.feishu.cn/document/uYjL24iN/uMTMuMTMuMTM/development-guide/step1#132c1aac)。

### 2. 复制凭证信息
前往 **凭证与基础信息** 页面,复制 `App ID` 和 `App Secret` 备用。

### 3. 复制事件回调的 Token 信息
前往 开发配置 → 事件与回调 → **加密策略** 页面,生成并复制 `Encrypt Key`(推荐启用,更安全)和 `Verification Token` 备用。

## 二、添加飞书集成
***
回到 Flashduty On-call **集成中心** 页面,选择 即时消息 → **飞书**,在表单中填入 `名称` 以及上一步复制的 `App ID`、`App Secret`、`Verification Token` 和 `Encrypt Key` 后,点击 **保存** 完成创建。
创建成功后,您将在列表中看到已添加的飞书集成。点击其名称进入详情页面,即可查看 **网页配置** 地址、**重定向 URL** 和 **消息卡片请求网址**,这些信息将在后续步骤中使用。

## 三、配置飞书应用
***
### 1. 开通并配置应用能力
1. 回到飞书开发者后台,进入刚才创建的飞书应用,进入 添加应用能力 → **按能力添加** 页面,同时开通 **网页应用** 和 **机器人** 能力。

2. 前往 **网页应用** 页面,配置 `桌面端主页` 和 `移动端主页`,内容均为集成详情中的 **网页配置** 地址。详见飞书开发文档 [配置应用主页地址](https://open.feishu.cn/document/uYjL24iN/uMTMuMTMuMTM/development-guide/step1#8366b844)。

3. 前往 事件回调 → **事件配置** 页面,配置 `订阅方式`(内容为集成详情中的 **消息卡片请求网址**)。然后,添加以下两项事件:
* `im.chat.disbanded_v1`
* `im.message.receive_v1`

4. 前往 事件回调 → **回调配置** 页面,配置 `订阅方式`(内容为集成详情中的 **消息卡片请求网址**)。然后,订阅以下两项回调:
* `card.action.trigger`
* `card.action.trigger_v1`

### 2. 添加重定向 URL 到飞书应用
进入 **安全设置** 页面,配置 `重定向URL`,内容为集成详情中的 **重定向 URL**。
详见飞书开发文档 [配置重定向 URL](https://open.feishu.cn/document/uYjL24iN/uYjN3QjL2YzN04iN2cDN?lang=zh-CN#c863e533)。

### 3. 申请应用权限
进入 **权限管理** 页面,为先前步骤创建的应用申请页面开头 [AISRE 所需权限](#aisre-permissions) 中列出的全部权限。请特别确认已开通 `im:message.p2p_msg:readonly` 和 `im:message.group_at_msg:readonly`,否则飞书不会向 Flashduty 推送单聊消息或群聊 @ 机器人消息。权限或事件配置变更后,需要重新发布应用后才会在线上生效。

## 四、应用发布与使用
完成上述所有配置后,请发布应用。待管理员审核通过后即可使用。详见飞书开发文档 [应用发布与使用](https://open.feishu.cn/document/uYjL24iN/uMTMuMTMuMTM/development-guide/step-4)。
为了确保所有人可以使用应用,需将应用 **可见范围** 调整为全部员工,再进行应用发布。

应用发布后,即可通过 **手机端** 或 **PC 端** 访问应用。首次访问需要登录并关联飞书与 Flashduty 账号,后续可以免登录使用。
飞书 → 工作台 → 搜索应用名称 → **打开应用**
飞书 → 工作台 → 搜索应用名称 → **打开应用**

## 五、配置作战室
> 确保应用已被授权使用页面开头列出的 [AISRE 所需权限](#aisre-permissions)。
完成先前步骤后,在 Flashduty On-call 集成配置页面的 **增强功能** 模块,勾选 **开启作战室** 即可启用该功能,无需额外配置。
同一时间仅支持在一个 IM 集成中开启作战室功能。如果你已在其他 IM 集成(如钉钉、Slack、企业微信)中启用了作战室,需要先在该集成中关闭后,才能在当前飞书集成中开启。
### AI SRE 控制项
在 **增强功能** 中分别配置以下 AI SRE 控制项,默认均为开启:
* **自动发起 AI 故障分析**:开启作战室后可配置;作战室创建成功后,自动发起一次 AI 故障分析。
* **允许群聊 @ AI SRE**:无需开启作战室即可配置,允许在此集成已接入的群聊中 @ AI SRE 发起对话;关闭后不会响应该入口。
* **普通群聊中 AI SRE 使用话题回复**:无需开启作战室即可配置。开启后,普通群聊中的每个话题对应一个独立 Session;作战室仍直接在群内回复。
如果账户尚未启用 AI SRE,以上配置暂不生效。
## 六、关联用户
在集成详情页的 **关联用户** 页签中,你可以查看团队成员与飞书账号的关联状态,并快速完成批量关联。
### 查看关联状态
关联用户列表展示所有团队成员及其关联状态。你可以通过以下方式筛选:
| 筛选项 | 说明 |
| :------ | :-------------- |
| **全部** | 查看所有团队成员 |
| **已关联** | 仅查看已完成飞书账号关联的成员 |
| **未关联** | 仅查看尚未关联飞书账号的成员 |
支持通过名称或邮箱搜索成员。
### 一键关联
当存在未关联的成员时,可以点击 **一键关联** 按钮。系统将尝试通过手机号或邮箱换取飞书开放平台的账号 ID 并自动关联,效果等同于成员使用相同信息在飞书平台登录 Flashduty。
成员完成关联后,系统才能向其推送飞书消息通知。如果关联失败,请确认成员的手机号或邮箱是否与飞书账号一致。
## 七、常见问题
前往 飞书 → 工作台 → 搜索应用名称 → **打开应用**,完成一次登录以关联飞书与 Flashduty 账号,系统才能获取用户身份进行消息推送。
* 确保账户已经完成关联。您可以前往 飞书 → 工作台 → 搜索应用名称 → **打开应用**,完成一次登录。如果已经登录过,请尝试点击右上角菜单,切换账户后重新登录以绑定账号
* 确保已购买足够的 License。已使用 License 情况,可以在 控制台 → **费用中心** 查看
* 前往飞书,在指定群聊会话中添加已创建的 Flashduty 机器人
* 回到分派策略配置页面,刷新后重新选择群聊列表

**调用量限制:**
| **飞书版本** | **调用总量/月** | **刷新时间** |
| :------: | :--------: | :------: |
| 基础免费版 | 10,000 次 | 每月 1 日 |
| 其他版本 | 不限制 | - |
**频控限制:**
| **场景** | **限制** |
| :------------: | :----------------- |
| 所有接口 | 每个应用最高频率 50 次/秒 |
| 发消息接口 | 每个应用最高频率 1000 次/分钟 |
| 群机器人 Webhook | 最高频率 100 次/分钟 |
| 给同一个用户或同一个群发消息 | 最高频率 5 次/秒 |
超出 API 调用量限制后,飞书应用将无法正常推送消息,建议合理使用通知渠道。详见 [飞书官方文档](https://open.feishu.cn/document/uAjLw4CM/ugTN1YjL4UTN24CO1UjN/platform-updates-/custom-app-api-call-limit)。
* 请再次检查是否为应用配置了页面开头列出的 [AISRE 所需权限](#aisre-permissions)
* 请参考 [作战室介绍文档](/zh/on-call/advanced/war-room) 的 **常见问题** 部分
# Microsoft Teams
Source: https://docs.flashduty.com/zh/on-call/integration/instant-messaging/microsoft-teams
通过集成 Microsoft Teams 第三方应用,您可以在 Microsoft Teams 内接收和响应告警
**版本要求**:IM 集成需要 On-call 专业版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/)
如果您的组织限制第三方应用,请先联系 Microsoft Teams 管理员允许使用 Flashduty。
如需了解 Teams 应用处理 Teams 用户、团队、频道、群聊和故障卡片数据的规则,请参阅《[Flashduty Microsoft Teams 应用隐私政策](/zh/compliance/microsoft-teams-app-privacy-policy)》和《[Flashduty Microsoft Teams 应用使用条款](/zh/compliance/microsoft-teams-app-terms-of-use)》。
## 一、数据和权限说明
Flashduty Teams 应用只在发送告警通知、完成关联配置和处理故障卡片操作所需的范围内处理 Teams 数据。
| 数据或能力 | 使用场景 |
| ---------------------------------------------- | ------------------------------------------------------------------- |
| Teams 用户 ID、Microsoft Entra ID(AAD Object ID) | 关联 Teams 用户与 Flashduty 用户;校验故障卡片操作人;向关联用户发送个人通知或操作反馈 |
| Team ID、Team 名称、Channel ID | 关联 Teams 团队或频道;把告警和故障通知发送到指定 Teams 频道;查询指定 Team 的详情和频道列表 |
| Group Chat ID、用户输入的 Chat 名称 | 关联 Teams 群聊;把告警和故障通知发送到指定群聊 |
| Conversation ID、Activity ID、Bot Framework 会话引用 | 在应用安装后发送、更新或回复 Teams 通知卡片 |
| Bot 指令和卡片动作 | 处理 `help`、`linkUser`、`linkTeam`、`linkChat` 指令,以及认领、解决、暂缓、自定义操作等卡片按钮 |
| Flashduty 告警和故障卡片数据 | 在 Teams 中展示告警或故障详情,并把卡片操作结果同步回 Flashduty |
Flashduty Teams 应用不会读取与 Flashduty 功能无关的普通 Teams 聊天内容。它只处理个人聊天中发送给 bot 的消息、团队或群聊中 @ bot 的消息、卡片按钮动作、应用安装和会话所需的引用信息,以及发送或更新 Flashduty 通知所需的数据。
当前应用包不申请用于读取全组织聊天内容的 Microsoft Graph 权限。如后续版本引入新的 Teams 权限或数据处理场景,Flashduty 将更新本文档和相关隐私说明。
## 二、从 Microsoft Teams 获取应用
在 Microsoft Teams 中选择 **Apps**,搜索 **Flashduty**,然后打开应用详情页。
选择 **Add**。根据使用场景,选择添加到团队/频道、群聊或个人聊天。
以下指令中的 `{ID}` 请替换为 Flashduty Microsoft Teams 集成 ID;`{ChatName}` 请替换为群聊名称。
## 三、关联团队 (Team)
在 Teams 中打开 **Apps**,找到 **Flashduty**,然后选择 **Add to a team**。
如果无法找到或添加应用,请联系 Microsoft Teams 管理员。
将应用添加到目标 Team。
此步骤必须选择目标 Team 的 General Channel,否则将无法发送故障到 Team 中。

在 Team 的 General Channel 中 @Flashduty 并发送 `linkTeam {ID}`,然后选择 **立即关联**。

如需解除该 Team 的关联,请在同一频道中发送 `@Flashduty unlinkTeam {ID}`。在响应卡片中选择 **Unlink in FlashDuty** 后,Flashduty 会自动解除关联并显示成功提示。
## 四、关联群聊 (Chat)
在 Teams 中打开 **Apps**,找到 **Flashduty**,然后选择 **Add to a chat**。
如果无法找到或添加应用,请联系 Microsoft Teams 管理员。
将应用添加到目标 Chat。

在群聊中 @Flashduty 并发送 `linkChat {ID} {ChatName}`,然后选择 **立即关联**。

如需解除该群聊的关联,请在同一群聊中发送 `@Flashduty unlinkChat {ID}`。在响应卡片中选择 **Unlink in FlashDuty** 后,Flashduty 会自动解除关联并显示成功提示。
## 五、消息卡片操作
当故障通知推送到 Microsoft Teams 后,通知卡片可包含以下交互操作;具体可用按钮以您收到的 Flashduty 卡片和后台配置为准:
* **认领(Acknowledge)**:标记您已开始处理该故障
* **解决(Resolve)**:将故障标记为已解决并关闭
* **暂缓(Snooze)**:暂时挂起故障,在指定时间后重新提醒
* **自定义操作(Custom Actions)**:触发您预先配置的自定义操作(如重启服务、回滚变更等)
作战室(War Room)功能目前不支持 Microsoft Teams。如果您需要使用作战室功能,请考虑使用 Slack、飞书、钉钉或企业微信集成。
## 六、关联用户
在 Teams 中打开 **Apps**,找到 **Flashduty**,然后选择 **Open**。
如果无法找到或打开应用,请联系 Microsoft Teams 管理员。
点击 **打开应用**。

在与 Flashduty 的个人聊天中发送 `linkUser {ID}`,然后选择 **立即关联**。

如需解除您的 Teams 账号关联,请在同一个人聊天中发送 `unlinkUser {ID}`。在响应卡片中选择 **Unlink in FlashDuty** 后,Flashduty 会自动解除关联并显示成功提示。已关联的当前用户也可以前往 **集成中心 → 即时消息 → Microsoft Teams → 关联用户**,点击 **解除我的关联**,再在确认框中选择 **确认**。
## 七、常见问题
请前往 集成中心 → 即时消息 → **Microsoft Teams**,检查团队和用户是否已成功关联。
请前往 集成中心 → 即时消息 → **Microsoft Teams**,在 **关联 Teams** 和 **关联用户** 中查看。
请在原始 Teams 上下文中使用对应指令:在 Team 频道中使用 `unlinkTeam {ID}`,在群聊中使用 `unlinkChat {ID}`,或在个人聊天中使用 `unlinkUser {ID}`。在响应卡片中选择 **Unlink in FlashDuty** 后,Flashduty 会自动解除对应关联。已关联的当前用户也可以在 **关联用户** 中点击 **解除我的关联**,再在确认框中选择 **确认**。
# Slack
Source: https://docs.flashduty.com/zh/on-call/integration/instant-messaging/slack
通过集成 Slack 第三方应用,您可以在 Slack 内接收和响应告警
**版本要求**:IM 集成需要 On-call 专业版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/)
## AISRE 所需权限
以下为 Slack IM 集成在开启 AISRE(包含基础通知、作战室、AI SRE 对话、AI 生成复盘和故障通知分派)时需要授予的完整权限清单。进入 Slack 应用 **OAuth & Permissions** 页面时,请确认已授权以下官方 scope 名称。对于已授权的 Slack 集成,如缺少权限,请重新授权。
### Bot Token Scopes
| 官方 scope 名称 | 用途 |
| :--------------------- | :------------------------------------ |
| `app_mentions:read` | 接收群聊中 @ 应用的消息,用于 AI SRE 对话入口 |
| `im:history` | 读取私聊历史消息,用于 AI SRE 上下文 |
| `chat:write` | 发送基础通知、作战室消息和 AI SRE 回复 |
| `chat:write.public` | 向应用尚未加入的公开频道发送通知和作战室消息 |
| `channels:read` | 读取公开频道信息和频道列表 |
| `channels:history` | 读取公开频道消息历史;AI SRE 上下文和 AI 生成复盘报告需要该权限 |
| `groups:read` | 读取私有频道信息和频道列表 |
| `groups:history` | 读取私有频道消息历史;AI SRE 上下文和 AI 生成复盘报告需要该权限 |
| `groups:write` | 创建和管理私有频道作战室 |
| `groups:write.invites` | 邀请成员加入私有频道作战室 |
| `users:read` | 读取用户基础信息,用于用户关联、展示和邀请 |
| `users:read.email` | 读取用户邮箱,用于用户关联 |
| `reactions:write` | 添加或删除消息表情反应,用于 AI SRE 处理状态确认 |
| `files:read` | 读取消息中的文件,用于 AI SRE 上下文和附件处理 |
### User Token Scopes
| 官方 scope 名称 | 用途 |
| :-------------- | :-------------------------- |
| `channels:read` | 读取授权用户可见的公开频道,用于频道列表和分派策略配置 |
如果您使用的是 Slack Incoming Webhook 方式的 Slack 机器人通知,而不是本页的 Slack App 集成,请在对应 Slack 应用中开启 Incoming Webhooks,并在 OAuth 流程中包含 `incoming-webhook` scope。
## 一、安装应用
访问 Flashduty On-call 集成中心 → 即时消息 → **Slack**,点击 **添加**。
在跳转的 Slack 页面,于右上角选择 **工作区**,然后点击 **允许**。

输入数据源名称,点击 **保存**。
## 二、配置作战室
> 确保应用已被授权使用页面开头列出的 [AISRE 所需权限](#aisre-permissions)。
完成先前步骤后,在 Flashduty On-call 集成配置页面的 **增强功能** 模块,勾选 **开启作战室** 即可启用该功能,无需额外配置。
### AI SRE 控制项
在 **增强功能** 中分别配置以下 AI SRE 控制项,默认均为开启:
* **自动发起 AI 故障分析**:开启作战室后可配置;作战室创建成功后,自动发起一次 AI 故障分析。
* **允许群聊 @ AI SRE 和 /fd 命令**:无需开启作战室即可配置,允许在此集成已接入的 Slack 群聊中 @ AI SRE 或使用 `/fd` 命令;关闭后两个入口都不会响应。
* **普通群聊中 AI SRE 使用话题回复**:无需开启作战室即可配置。开启后,普通群聊中的每个话题对应一个独立 Session;作战室仍直接在群内回复。
如果账户尚未启用 AI SRE,以上配置暂不生效。
## 三、关联用户
在集成详情页的 **关联用户** 页签中,你可以查看团队成员与 Slack 账号的关联状态,并快速完成批量关联。
### 查看关联状态
关联用户列表展示所有团队成员及其关联状态。你可以通过以下方式筛选:
| 筛选项 | 说明 |
| :------ | :------------------- |
| **全部** | 查看所有团队成员 |
| **已关联** | 仅查看已完成 Slack 账号关联的成员 |
| **未关联** | 仅查看尚未关联 Slack 账号的成员 |
支持通过名称或邮箱搜索成员。
### 一键关联
当存在未关联的成员时,可以点击 **一键关联** 按钮。系统将尝试通过手机号或邮箱换取 Slack 开放平台的账号 ID 并自动关联,效果等同于成员使用相同信息在 Slack 平台登录 Flashduty。
成员完成关联后,系统才能向其推送 Slack 消息通知。如果关联失败,请确认成员的邮箱是否与 Slack 账号一致。
## 四、常见问题
* 同一时间仅支持在一个 IM 集成中开启作战室功能。如果您已在其他 IM 集成(如钉钉、飞书、企业微信)中启用了作战室,需要先在该集成中关闭后,才能在当前 Slack 集成中开启
* 开启作战室时,系统会自动验证当前 Slack 应用是否具备作战室所需的全部权限。如果检测到缺少必要权限,页面会显示一条警告提示,并提供 **重新授权** 链接
* 点击 **重新授权** 链接后,系统会跳转到 Slack 授权页面,请求页面开头列出的 [AISRE 所需权限](#aisre-permissions)。完成授权后,页面会自动返回 Flashduty
* 如果您的 Slack 集成是在作战室功能上线之前完成授权的,首次开启时通常需要重新授权以补充新增权限。重新授权不会影响已有的集成配置和用户关联
* 确保 [**安装应用**](#install-app) 步骤已成功完成且未报错
* 进入相关的 Slack 频道,执行 `/invite @Flashduty` 命令
* 当看到 `已加入` 或 `已由 xxx 添加至 xxx` 的提示时,即表示添加成功
* 将应用授权人添加到公共频道中
* 参考上一问题的方法,将应用添加到频道中
请重新操作。这可能是由于服务器与 Slack 通信异常导致授权失败。请返回添加数据源页面重试。如果重试后仍然报错,请联系客服。
请重新操作。这可能是由于 Flashduty 服务器在获取永久授权码时与 Slack 通信异常。请返回添加数据源页面重试。如果重试后仍然报错,请联系客服。
请重新操作,这可能是 Slack 服务暂时出现问题。如果重试后仍然报错,请联系客服。
请重新操作。这可能是服务器与 Slack 通信超时。如果重试后仍然报错,请联系客服。
请重新操作。这可能是 Flashduty On-call 服务端出现错误(例如,数据源被关闭)。如果重试后仍然报错,请联系客服。
请重新操作。如果重试后仍然报错,请联系客服以记录和解决新问题。
* 请再次检查是否为应用配置了页面开头列出的 [AISRE 所需权限](#aisre-permissions)
* 对于之前授权的 Slack IM 集成,需要您在 Flashduty On-call 集成配置页中对 Slack 手动进行重新授权,以使应用获得 AISRE 所需权限
* 请参考 [作战室介绍文档](/zh/on-call/advanced/war-room) 的 **常见问题** 部分
# 企业微信
Source: https://docs.flashduty.com/zh/on-call/integration/instant-messaging/wecom
通过集成企业微信第三方应用,实现在企业微信端接收和响应告警的能力
**版本要求**:IM 集成需要 On-call 专业版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/)
本文档支持 [集成第三方应用](#third-party) 或 [集成企业自建应用](#self) 两种方式。
**集成第三方应用** 和 **集成自建应用** 两种方式只需按需配置其中一种。
## 一、集成第三方应用
Flashduty 作为企业微信服务商,为您提供 Flashduty 应用的长期免费版本。该应用需要获得企业微信接口调用许可才能使用(免密登录 + 消息发送)。该许可目前支持 **最多 60 天** 免费,超出该使用时长后,Flashduty 需要为您购买企业微信许可,您方可继续使用。
1. 访问 [企业微信管理后台](https://work.weixin.qq.com/wework_admin/frame#apps),进入 应用管理 → **应用** 页面,点击 **添加第三方应用**。

2. 在搜索栏输入 `Flashduty`,检索到应用后,点击 **添加** 按钮。

3. 修改应用 **可见范围**,推荐选择全员或具体部门节点,以避免新增企业成员时仍需修改。然后,点击 **同意以上授权并添加** 完成安装。

4. 访问 [企业微信管理后台](https://work.weixin.qq.com/wework_admin/frame#apps),进入 **我的企业** 页面,获取 `企业 ID`。

5. 返回 Flashduty On-call 集成配置页面,填写上一步获取的 `企业 ID`,点击 **保存** 完成集成。
## 二、集成企业自建应用
1. 访问 [企业微信管理后台](https://work.weixin.qq.com/wework_admin/frame#apps),进入 应用管理 → **应用** 页面,点击 **创建应用**。

2. 配置 **应用 Logo**、**应用名称** 和 **应用可见范围**。

3. 返回 Flashduty On-call 集成配置页面,根据您的实际情况选择企业微信是否为 `非私有化部署版本`。
若您的企业微信为私有化部署版本,则需要在配置页面中填写 `Endpoint`。此地址需要能够被 Flashduty 服务访问,您可以考虑为其设置 **白名单授权**。
4. 访问 [企业微信管理后台](https://work.weixin.qq.com/wework_admin/frame#apps),进入 **我的企业** 页面,获取 `企业 ID`,并将其填写至 Flashduty On-call 集成配置页面。
5. 返回 [企业微信管理后台](https://work.weixin.qq.com/wework_admin/frame#apps),进入 **应用管理** 页面,点击您所创建的应用进入详情页。获取页面中的 `AgentId`,并将其填写至 Flashduty On-call 集成配置页面。
6. 在应用详情页,获取 `Secret`,并将其填写至 Flashduty On-call 集成配置页面。
7. 在应用详情页,进入 **网页授权及 JS-SDK** 页面,点击 **设置可信域名**,并按要求配置。
可信域名需要指向 Flashduty On-call 的后端地址 `{api_host}`(可通过 CNAME 或代理转发实现)。关于可信域名的要求,详见企业微信官方文档 [《企业内部开发配置域名指引》](https://open.work.weixin.qq.com/wwopen/common/readDocument/40754)。

返回 Flashduty On-call 集成配置页面,填写该域名,并完成验证。
8. 在应用详情页,进入 **接收消息** 页面,并 **设置 API 接收**。分别对 `Token` 和 `EncodingAESKey` 点击 **随机获取**,然后复制并保存所生成的值。

返回 Flashduty On-call 集成配置页面,填写已保存的 `Token` 和 `EncodingAESKey`,点击 **保存** 完成集成。
9. 复制 Flashduty On-call 集成详情页中的 `回调地址`,返回企业微信刚才的 **接收消息** 页面。在 **API 接收** 设置中,填入该 `回调地址` 以及上一步保存的 `Token` 和 `EncodingAESKey`,然后点击 **保存**。

10. 配置**前端可信域名**
可信域名需要指向 Flashduty On-call 的前端地址 `console.flashcat.cloud`(可通过 CNAME 或代理转发实现)。关于可信域名的要求,详见企业微信官方文档 [《企业内部开发配置域名指引》](https://open.work.weixin.qq.com/wwopen/common/readDocument/40754)。
前端可信域名校验通过后将生成的**主页地址**配置到企微应用的**工作台应用主页**

11. 配置**可信 IP 地址**:`47.93.12.134`

## 三、配置作战室
作战室功能仅支持在 **企业自建应用** 模式下开启。
完成先前步骤后,在 Flashduty On-call 集成配置页面的 **增强功能** 模块,勾选 **开启作战室** 即可启用该功能,无需额外配置。
同一时间仅支持在一个 IM 集成中开启作战室功能。如果你已在其他 IM 集成(如钉钉、飞书、Slack)中启用了作战室,需要先在该集成中关闭后,才能在当前企业微信集成中开启。
### AI SRE 控制项
开启 **作战室** 后,配置页会显示以下 AI SRE 控制项,默认均为开启:
* **自动发起 AI 故障分析**:作战室创建成功后,自动发起一次 AI 故障分析。
* **允许群聊 @ AI SRE**:允许在此集成已接入的群聊中 @ AI SRE 发起对话;关闭后不会响应该入口。
如果账户尚未启用 AI SRE,以上配置暂不生效。
## 四、配置 AISRE
如需在企业微信中使用 AISRE,请先在 Flashduty 企业微信集成中开启 **作战室** 功能,然后额外创建一个智能机器人,并使用 API 模式接入 Flashduty。
1. 在企业微信应用左侧进入 **工作台**,找到 **智能机器人**,进入机器人管理页面。
2. 创建一个新的智能机器人,创建方式选择 **手动创建**,然后选择 **使用 API 模式创建**。
建议由企业内部成员创建智能机器人。即使可见范围设置为 **企业内部全体成员**,其他成员仍需要创建者通过分享后才能看到该机器人。
3. 在智能机器人的 **API 配置** 页面,连接方式选择 **使用 URL 回调**,并填入 Flashduty 集成配置页提供的 `URL`。
4. 在企业微信智能机器人的 API 配置页中生成 `Token` 和 `Encoding-AESKey`,并将相同的值填写到 Flashduty 企业微信集成配置页。请确保企业微信和 Flashduty 中的 `Token`、`Encoding-AESKey` 完全一致,然后分别保存两边配置。
企业微信暂不支持在创建作战室后自动将智能机器人拉入群聊。使用 AISRE 时,需要手动将智能机器人添加到对应作战室群聊中。
## 五、关联用户
在集成详情页的 **关联用户** 页签中,你可以查看团队成员与企业微信账号的关联状态,并快速完成批量关联。
### 查看关联状态
关联用户列表展示所有团队成员及其关联状态。你可以通过以下方式筛选:
| 筛选项 | 说明 |
| :------ | :---------------- |
| **全部** | 查看所有团队成员 |
| **已关联** | 仅查看已完成企业微信账号关联的成员 |
| **未关联** | 仅查看尚未关联企业微信账号的成员 |
支持通过名称或邮箱搜索成员。
### 一键关联
当存在未关联的成员时,可以点击 **一键关联** 按钮。系统将尝试通过手机号或邮箱换取企业微信开放平台的账号 ID 并自动关联,效果等同于成员使用相同信息在企业微信平台登录 Flashduty。
成员完成关联后,系统才能向其推送企业微信消息通知。如果关联失败,请确认成员的手机号或邮箱是否与企业微信账号一致。
## 六、集成企微智能体(AI SRE)
企微智能体(AI Bot)是企业微信提供的 AI 对话机器人功能。通过将 Flashduty AI SRE 与企微智能体对接,您的团队可以在企微单聊或群聊中直接通过 @ 智能体发起 AI 故障排查会话,无需离开企业微信。
智能体集成使用**独立于普通应用的凭据**(Bot Token 和 Bot EncodingAESKey)。请勿将 [集成企业自建应用](#self) 步骤 8 中生成的 Token / EncodingAESKey 填入此处——两套凭据彼此独立,混用将导致签名验证失败。
AI SRE 功能需要账户开通对应权限。如未开通,企微智能体收到消息后将不作任何响应。
### 配置步骤
访问 [企业微信管理后台](https://work.weixin.qq.com/wework_admin/frame#apps),进入 **应用管理 → AI 助理** 页面,点击 **创建 AI 助理**(智能体),完成基础信息配置(名称、头像、可见范围)。
进入已创建智能体的详情页,找到 **接收消息** 配置区域,分别对 `Token` 和 `EncodingAESKey` 点击 **随机生成**,然后复制并妥善保存这两个值。
这两个值仅属于该智能体,与您在企业微信自建应用中配置的 Token / EncodingAESKey **完全不同**。
返回 Flashduty On-call 企业微信集成详情页,在 **AI SRE 智能体** 配置区域,将上一步获得的 `Bot Token` 和 `Bot EncodingAESKey` 分别填入对应字段,点击 **保存**。
保存成功后,页面会显示该集成的 `integration_key`(即集成密钥)。
复制 Flashduty On-call 集成详情页中的 **智能体回调地址**,格式为:
```
https:///event/push/wecom/bot?integration_key=
```
返回企业微信管理后台,进入该智能体的 **接收消息** 设置,将回调地址、Token 和 EncodingAESKey 填入对应字段,点击 **保存**。
企业微信会向该地址发送一次 GET 请求进行 URL 验证(echostr 校验),Flashduty 服务器会自动完成验证应答。
### 使用方式
配置完成后,在企微单聊或群聊中 **@ 您的智能体**,输入问题或故障描述,即可触发 AI SRE 会话。智能体支持以下消息类型:
| 类型 | 说明 |
| :------- | :--------------------- |
| **文本** | 直接提问或描述问题 |
| **图片** | 发送截图,AI 将解析图片内容进行分析 |
| **文件** | 发送日志或配置文件,AI 将读取内容辅助排查 |
| **引用回复** | 引用上一条消息追问,AI 会结合上下文作答 |
企业微信智能体采用**拉取式流式响应**(stream polling):AI 生成回复时,企业微信客户端会定期向回调地址发送 `msgtype=stream` 请求拉取最新内容,直到 AI 回复完成。这是企业微信智能体的平台机制,用户无需额外配置。
### 常见问题
请按以下顺序排查:
1. 确认账户已开通 AI SRE 功能权限
2. 确认回调地址中的 `integration_key` 与 Flashduty 集成详情页显示的值完全一致
3. 确认 Flashduty 集成配置页中填写的 `Bot Token` 和 `Bot EncodingAESKey` 与智能体详情页 **接收消息** 中的值一致,而非来自企业微信自建应用
4. 在企业微信管理后台查看智能体的回调日志,确认请求是否到达以及是否有错误码
* 确认 Flashduty 服务能够被企业微信服务器正常访问(公网可达)
* 确认填写的 `Token` 和 `EncodingAESKey` 与 Flashduty 集成配置页中保存的值完全一致
* 确认回调地址中的 `integration_key` 参数正确,且对应的集成处于启用状态
这通常意味着 Bot Token 或 Bot EncodingAESKey 填写有误。请注意:智能体的 Token / EncodingAESKey 与企业微信自建应用(普通 IM 集成)的 Token / EncodingAESKey **是两套独立凭据**,请在智能体详情页的 **接收消息** 区域重新生成并更新至 Flashduty 集成配置。
## 七、常见问题
* 请检查您是否已完成应用的安装步骤。例如,您是否可以在企业微信工作台中看到 Flashduty On-call 应用
* 请检查您是否正确配置了 `Corp ID`
1. 登录企业微信客户端(桌面端和移动端均可),进入 **工作台**,找到并打开 Flashduty 应用
2. 首次进入应用需要登录。选择您的成员账号,通过密码或单点登录方式登入成功后,即可完成 Flashduty 账号与企业微信账号的关联
3. 后续进入应用将自动免密登录
1. 发送通知前,必须参照上一问题完成账户关联
2. 进入指定协作空间,导航至 `分派策略` → **个人渠道**,选择 `企业微信` 作为通知方式即可
3. Flashduty On-call 支持对企业微信通知内容进行自定义。您可以前往 **模板管理** 页面,设定自定义模板
自定义区域最多可展示 8 行,超出部分将被企业微信截断。

* 点击卡片消息,可直接进入告警详情页面
* 点击 **开始处理**,可直接将告警置为 `处理中` 状态
* 点击 **直接关闭**,可直接将告警置为 `已关闭` 状态
* 点击 **屏蔽 2 小时**,可直接将告警屏蔽 2 小时。如果想屏蔽更长时间,可点击卡片右上角的 `...` 查看更多屏蔽选项
根据企业微信的限制,一次卡片交互后,72 小时内只可更新一次。每一次按钮操作,都视为一次交互。
当告警状态发生变化时,Flashduty On-call 会请求更新卡片内容。当告警状态频繁变化时,可能因超出更新次数限制导致卡片无法实时更新。此时,您可以点击 **刷新** 按钮,手动获取一次更新卡片状态的机会。
Mac 桌面端默认使用企业微信的内置浏览器打开链接。您可以尝试使用快捷键 `ctrl` + `command` + `shift` + `d` 开启调试模式,然后选择 **调试** → **浏览器、webView 相关** → **系统浏览器打开网页**,来更改链接的打开方式。使用相同的快捷键可以关闭调试模式,设置将会保留。
请联系 Flashduty 客服或您的专属技术支持,为您购买并开通许可。
请参考 [作战室介绍文档](/zh/on-call/advanced/war-room) 的 **常见问题** 部分。
请确认**应用主页**的 URL 中的 `redirect_uri` 参数中的域名是否完成企业微信要求的域名归属认证,详见企业微信官方文档 [《企业内部开发配置域名指引》](https://open.work.weixin.qq.com/wwopen/common/readDocument/40754)。
# Link 集成
Source: https://docs.flashduty.com/zh/on-call/integration/other-integration/link
通过 Link 集成,可直接从故障属性、标签等信息中获取访问外部链接所需的关键参数,实现快速访问
通过 Link 集成,可直接从故障属性、标签等信息中获取访问外部链接所需的关键参数,实现快速访问。
## 配置说明
Link 集成功能支持从故障属性、标签等信息中提取关键参数,实现与外部系统的快速跳转。通过自动化填充和跳转,避免了手动输入,提高了问题定位与处理的效率。该功能适用于故障排查、性能监控和系统调试等场景,有助于优化运维流程,提升响应速度与准确性。
### 打开方式
#### 1. 弹窗
在故障详情的当前页面中弹出窗口,保持原有界面状态,适合快速查看或操作后返回。
#### 2. 新标签页
在浏览器新标签中打开链接,适用于需要保留当前操作上下文并同时访问外部内容的场景。
### URL 配置
URL 的参数引用内容为标签时以 `labels.` 开头;引用内容为自定义字段时,以 `fields.` 开头;引用内容为故障属性时,直接引用即可,如 `title`、`severity` 等。
#### 故障标签中获取
支持通过 的方式从参数中动态取值,用于构造请求地址。例如参数值从故障标签中自动填充,无需手动输入:
```text theme={null}
https://cmdb.com/vm?sn=${labels.sn}
```
在上述示例中, 表示将故障中的 `sn` 标签值动态注入至 URL 中。如果故障数据中包含 `sn=VM123456`,则最终请求地址为:
```text theme={null}
https://cmdb.com/vm?sn=VM123456
```
#### 自定义字段中获取
支持通过 的方式从参数中动态取值,用于构造请求地址。例如参数值从自定义字段中自动填充,无需手动输入:
```text theme={null}
https://cmdb.com/vm?sn=${fields.sn}
```
在上述示例中, 表示将故障中的 `sn` 自定义字段值动态注入至 URL 中。如果自定义字段数据中包含 `sn=VM123456`,则最终请求地址为:
```text theme={null}
https://cmdb.com/vm?sn=VM123456
```
### 注意事项
1. 当引用的内容不存在时,Link 集成会正常生成对应的链接,但无法获取到值
2. 同一个协作空间至多绑定三个 Link 集成
3. 注意引用语法,如未按照要求进行书写引用变量,会导致无法正常获取对应值
# Authing
Source: https://docs.flashduty.com/zh/on-call/integration/sso/authing
通过 Authing 平台配置 OIDC、SAML2.0 或 CAS 协议实现单点登录
[Authing](https://www.authing.cn/) 是一家提供身份识别和访问控制管理的供应商,通过 Authing 平台,可实现以 OIDC、SAML2.0 或 CAS 协议的方式登录 Flashduty 管理控制台。
## 准备工作
如果是新注册用户,需先创建用户池,根据提示创建即可。
* 选择标准 web 应用
* 填写应用名称
* 填写认证地址(SSO 登录时跳转的地址)


| 字段 | 描述 |
| ---------- | ---------------------------- |
| App ID | 对应 Flashduty 的 Client ID |
| APP Secret | 对应 Flashduty 的 Client Secret |
| Issuer | 对应 Flashduty 的 Issuer |
| 认证地址 | 通过 SSO 登录时跳转的地址 |
## 协议配置
### 1. 开启单点登录配置
打开 [Flashduty](https://console.flashcat.cloud) 控制台并开启单点登录配置。

### 2. 配置相关信息
将 Authing 应用的相关信息复制到对应的填写框中:

将 Redirect URL 域名复制到 Authing 的登录回调 URL 中:

### 3. 更改 Authing 配置
将 id\_token 签名算法更改为 **RS256**:

配置登录控制:

更改权限:

### 4. 创建用户并测试登录
Flashduty 默认通过邮箱关联成员,建议用邮箱创建用户。新建 SSO 配置也可以配置稳定用户 ID 字段进行关联,详见 [单点登录配置](/zh/platform/configure-sso)。
在 Authing 中创建用户:

使用 SSO 地址测试登录:

您也可以访问 `console.flashcat.cloud` 通过 SSO 的方式登录。
SSO 地址跳转到登录页面后,使用在 Authing 创建的用户登录 Flashduty 控制台:

可以新创建应用或者在已有的应用中修改,这里通过修改应用进行演示。
### 1. 协议配置
选择 SAML2.0:

将 Flashduty 的单点登录协议改成 SAML 协议,并复制 ACS 地址:

将 ACS 地址复制到 Authing 应用中后,点击保存并修改协议类型:

### 2. 在 Flashduty 中配置
下载 metadata 数据,点击链接并保存到本地:

上传到 Flashduty 的单点登录配置中并保存:

### 3. 测试登录
参考 OIDC 协议的登录流程进行测试:

两个平台在配置时有穿插,请务必小心不要遗忘关键信息。如在配置过程中有任何问题,可以联系 Flashduty 技术支持协助。
### 1. 开启单点登录配置
打开 [Flashduty](https://console.flashcat.cloud) 控制台并开启单点登录配置。

### 2. 配置相关信息
将 Authing 应用的相关信息复制到对应的填写框中:

将 Redirect URL 复制到 Authing 的登录回调 URL 中:

### 3. 更改 Authing 配置
按图配置:

配置登录控制:

更改权限:

### 4. 创建用户并测试登录
Flashduty 默认通过邮箱关联成员,建议用邮箱创建用户。新建 SSO 配置也可以配置稳定用户 ID 字段进行关联,详见 [单点登录配置](/zh/platform/configure-sso)。
在 Authing 中创建用户:

使用 SSO 地址测试登录:

SSO 地址跳转到登录页面后,使用在 Authing 创建的用户登录 Flashduty 控制台:

# Keycloak
Source: https://docs.flashduty.com/zh/on-call/integration/sso/keycloak
通过 Keycloak 配置 SAML2.0 或 OIDC 协议实现单点登录
Keycloak 是一个开源的身份和访问管理解决方案,提供了一套全面的工具和功能,帮助开发人员快速实现安全的用户身份验证和授权机制。
本篇文章不涉及部署和讲解 Keycloak 相关内容,如需了解更多信息,请参考 [官方文档](https://www.keycloak.org/)。
## 协议配置
### 1. 获取 ACS 地址
登录 Flashduty 控制台,获取 ACS 地址(后续步骤会用到)。
路径:**访问控制 => 单点登录 => 设置 => SAML2.0 协议 => Flashduty 服务提供商信息 => Assertion Consumer Service URL**

### 2. 创建 Client
登录 Keycloak 控制台,路径:**Clients => Create client**
* **Client Type**:选择 SAML 协议
* **Client ID**:填写 `flashcat.cloud`(固定值,不可更改)

**Valid redirect URIs**:填写从 Flashduty 获取的 ACS 地址

### 3. 配置 Client 相关信息
**Name ID format** 更改为 email 类型:

**Client signature required** 设置为关闭状态:

**创建 Client scope**:
创建之前需要先删除之前 OpenID Connect 协议的用户,创建完成设置为 Default。
参考下图依次创建 email/phone/username 三种类型:

创建完成的效果:

**将添加的用户加入到 Client 中**:


**配置 email/phone/username 映射器**(以 email 为例,其他按照相同步骤配置):



### 4. 下载 XML 文件
下载的文件是一个压缩包,在本地解压后会有两个 xml 文件,只需要 `idp-metadata.xml` 文件即可。
在 **Client => Action** 中下载到本地:

上传 XML 文件到 Flashduty 的单点登录配置中:

### 5. 创建用户并测试登录
创建用户(一定要绑定一个邮箱地址):

**登录测试**:访问 `console.flashcat.cloud`,选择 SSO 登录,在域名处填写单点登录配置中的登录域名前缀。

### 1. 获取 Redirect URL
登录 Flashduty 控制台,获取 Redirect URL(后续步骤会用到)。
路径:**访问控制 => 单点登录 => 设置 => OIDC 协议 => Flashduty 服务提供商信息 => Redirect URL**

### 2. 创建 Client
登录 Keycloak 控制台,创建新 Client:
* **Client Type**:选择 OIDC 协议
* **Client ID**:没有特殊要求

**Client authentication**:保持开启状态

**Valid redirect URIs**:填写第 1 步获取的 Redirect URL 地址

### 3. 获取 Client 相关信息
* **Client ID**:创建 Client 时填写的 ID
* **Client Secret**:在 **Client 详情 => Credentials** 卡片中查看

* **Issuer**:在 **Realm settings => Endpoints => OpenID Endpoint Configuration** 中查看

### 4. 配置 Flashduty 单点登录
将上述信息填入 Flashduty 单点登录配置:

配置完成后,登录测试参考 SAML2.0 协议的第 5 步即可。
# OpenLDAP
Source: https://docs.flashduty.com/zh/on-call/integration/sso/openldap
通过 Docker Compose 搭建 OpenLDAP 并集成到 Flashduty
LDAP 集成登录仅 **私有化版本** 支持。
## 快速了解
LDAP(Lightweight Directory Access Protocol,轻量级目录访问协议)是一种基于 X.500 标准的协议,用于访问和维护分布式目录服务。LDAP 使得用户和应用程序能够查询、浏览和搜索存储在目录中的信息,如用户身份信息、网络资源等。
LDAP 通常运行在 TCP/IP 协议栈上,特别是使用 TCP 端口 389(未加密通信)和 636(加密通信,使用 LDAPS)。
**LDAP 的核心特性:**
* **树状结构**:LDAP 数据组织成树状结构,称为 DIT(Directory Information Tree),便于进行层次化的搜索和浏览
* **条目和属性**:LDAP 中的每个条目(Entry)包含多个属性(Attribute),属性有类型和值,例如 `cn` 代表通用名称(Common Name),`mail` 代表电子邮件地址
OpenLDAP 是一个开源的 LDAP 实现,由于其开源和灵活性,成为了许多企业和组织的首选。
本文基于环境中已经支持 Docker 和 Docker Compose,如果环境不支持,请先自行安装。
## Docker Compose 配置
```yaml docker-compose.yml theme={null}
version: '1'
networks:
go-ldap-admin:
driver: bridge
services:
openldap:
image: osixia/openldap:1.5.0
container_name: go-ldap-admin-openldap
hostname: go-ldap-admin-openldap
restart: always
environment:
TZ: Asia/Shanghai
LDAP_ORGANISATION: "flashduty.com"
LDAP_DOMAIN: "flashduty.com"
LDAP_ADMIN_PASSWORD: "password"
volumes:
- ./openldap/ldap/database:/var/lib/ldap
- ./openldap/ldap/config:/etc/ldap/slapd.d
ports:
- 389:389
networks:
- go-ldap-admin
phpldapadmin:
image: osixia/phpldapadmin:0.9.0
container_name: go-ldap-admin-phpldapadmin
hostname: go-ldap-admin-phpldapadmin
restart: always
environment:
TZ: Asia/Shanghai
PHPLDAPADMIN_HTTPS: "false"
PHPLDAPADMIN_LDAP_HOSTS: go-ldap-admin-openldap
ports:
- 8088:80
volumes:
- ./openldap/phpadmin:/var/www/phpldapadmin
depends_on:
- openldap
links:
- openldap:go-ldap-admin-openldap
networks:
- go-ldap-admin
```
请将 `password` 替换成您想要设置的密码。
## 服务启动
将上述配置文件保存为 `docker-compose.yml`,在配置文件所在的目录,打开终端运行以下命令:
```bash theme={null}
docker-compose up
```
```bash theme={null}
docker-compose up -d
```
**查看服务状态:**
```bash theme={null}
docker-compose ps
```
**停止服务:**
```bash theme={null}
docker-compose down
```
## 登录 OpenLDAP
在浏览器中访问 `http://ip:8088/`,使用以下凭据登录:
| 字段 | 值 |
| --- | ------------------------------ |
| 用户名 | `cn=admin,dc=flashduty,dc=com` |
| 密码 | 您设置的密码 |
## OpenLDAP 配置
### 添加组和用户

在 **用户路径**(例如上图 `ou=people` 下的 `cn=flash duty`)=> **Add new attribute** => 选择 **Email**,为用户添加 Email 属性。若已存在请忽略。
## Flashduty 集成
结合上述 OpenLDAP 配置,Flashduty 集成信息如下图所示:

上述字段的含义与描述请参考 [配置单点登录](/zh/platform/configure-sso)。
配置完成后,点击设置抽屉底部的 **连接检测** 按钮,验证 Flashduty 能否成功连接到 OpenLDAP 服务器。连接成功后再点击 **保存**。
# 告警 Webhook
Source: https://docs.flashduty.com/zh/on-call/integration/webhooks/alert-webhook
配置告警 Webhook,当告警发生特定操作时,系统通过 HTTP 回调您配置的地址
**版本要求**:此功能需要 On-call 标准版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/)
配置告警 Webhook,当告警发生特定操作(如触发、关闭)时,系统通过 HTTP 回调您配置的地址。回调内容将包含告警最新关键信息,您可以与自研工具进行集成。
## 一、事件类型
目前支持以下事件类型,未来可能会增加。
| 事件类型 | 释义 |
| :-------: | :------------------------------------------ |
| a\_new | 集成推送新事件,触发一条新告警 |
| a\_update | 集成推送新事件,合并到一条告警,并更新告警信息(严重程度、状态、labels、描述等) |
| a\_merge | 合并告警至故障 |
| a\_close | 手动关闭告警(系统事件,当告警被手动关闭时由系统自动触发,无法在 UI 中勾选) |
## 二、推送描述
### 请求方式
POST, Content-Type:"application/json"
### 请求 Payload:
| 字段 | 类型 | 必含 | 释义 |
| :---------: | :---------------: | :-: | :----------------------------------- |
| event\_time | int64 | 是 | 事件发生`毫秒时间戳` |
| event\_type | string | 是 | 事件类型,枚举值见[事件类型](#EventTypes) |
| event\_id | string | 是 | 事件 ID,`同一个事件可能因为超时等原因重试多次,接收方需要能够去重` |
| person | [Person](#Person) | 否 | 操作人,仅人为动作时存在 |
| alert | [Alert](#Alert) | 是 | 告警详情 |
**Person**:
| 字段 | 类型 | 必含 | 释义 |
| :----------: | :----: | :-: | :---- |
| person\_id | int64 | 是 | 人员 ID |
| person\_name | string | 是 | 人员名称 |
| email | string | 是 | 邮件地址 |
**Alert**:
| 字段 | 类型 | 必含 | 释义 |
| :----------------: | :-------------------: | :-: | :------------------------------------------------------ |
| alert\_id | string | 是 | 告警 ID |
| data\_source\_id | int64 | 是 | 集成 ID |
| data\_source\_name | string | 是 | 集成名称 |
| data\_source\_type | string | 是 | 集成类型 |
| channel\_id | int64 | 是 | 协作空间 ID |
| channel\_name | string | 是 | 协作空间名称 |
| title | string | 是 | 告警标题 |
| title\_rule | string | 否 | 标题生成规则 |
| description | string | 否 | 告警描述 |
| alert\_key | string | 是 | 告警关联依据 |
| alert\_severity | string | 是 | 严重程度,枚举值:Critical,Warning,Info |
| alert\_status | string | 是 | 告警状态,枚举值:Critical,Warning,Info,Ok |
| progress | string | 是 | 处理进度,枚举值:Triggered,Closed |
| created\_at | int64 | 是 | 创建时间 |
| updated\_at | int64 | 是 | 更新时间 |
| start\_time | int64 | 是 | 首次触发时间(平台接收到的首个事件的时间),Unix 秒时间戳 |
| last\_time | int64 | 是 | 最新事件时间(平台接收到的最新事件时间),Unix 秒时间戳 |
| end\_time | int64 | 否 | 告警恢复时间(平台上一次接收到结束类型事件的时间),Unix 秒时间戳,默认为 0 |
| close\_time | int64 | 否 | 关闭时间,不同于 end\_time,这个是处理进度的关闭,不代表告警真的恢复。Unix 秒时间戳,默认为 0 |
| labels | map\[string]string | 否 | 标签 KV,Key 和 Value 均为字符串 |
| event\_cnt | int64 | 否 | 关联事件个数 |
| incident | [Incident](#Incident) | 否 | 所属故障 |
**Incident**:
| 字段 | 类型 | 必含 | 释义 |
| :----------: | :----: | :-: | :---- |
| incident\_id | string | 是 | 故障 ID |
| title | string | 是 | 故障标题 |
### 请求响应
HTTP status code 为 200,认为推送成功。
### 请求示例
```
curl -X POST 'https://example.com/alert/webhook?a=a' \
-H 'Content-Type: application/json' \
-H 'X-Customize-Header-A: a' \
-d '{
"alert":{
"alert_id":"645c3affd2b92d989a0bd824",
"alert_key":"d21d9e3126f5ae94",
"alert_severity":"Warning",
"alert_status":"Warning",
"channel_id":1163577812973,
"channel_name":"订单系统",
"close_time":0,
"created_at":1683766015,
"data_source_id":1571358104973,
"data_source_name":"阿里云 SLS",
"data_source_ref_id":"",
"data_source_type":"aliyun-sls.alert",
"description":"测试发送到Flashduty告警触发",
"end_time":0,
"event_cnt":1,
"incident":{
"incident_id":"645db17c9759374196929314",
"title":"123123123"
},
"labels":{
"a":"a",
"alert_type":"sls_alert",
"alert_url":"https://sls.console.aliyun.com/lognext/project/sls-api-testing/alert/alert-1683548531-071659",
"aliuid":"1082109605037616",
"check":"测试发送到Flashduty",
"fire_results":"{\"_col0\":\"true\"}",
"fire_results_count":"1",
"project":"sls-api-testing",
"raw_condition":"Count:__count__ \u003e 0; Condition:",
"region":"cn-beijing",
"resource":"d18195cd567c6e8b-5fb6a5e6fb8ad-1f269e0",
"severity":"6"
},
"last_time":1683809153,
"progress":"Triggered",
"start_time":1683766013,
"title":"测试发送到Flashduty告警触发",
"title_rule":"$resource::$check",
"updated_at":1683809170
},
"event_id":"ffcf1d47a8d853dc800d000c87e5568b",
"event_time":1683890681639,
"event_type":"a_merge",
"person":{
"email":"zhangsan@flashcat.cloud",
"person_id":82138731581973,
"person_name":"快猫星云"
}
}' -v
```
## 三、配置指南
进入 **集成中心** → **Webhook** → 添加或编辑 **告警 Webhook** 集成。
### 基础设置
填写集成名称和描述,便于后续管理。
### Webhook 设置
| 配置项 | 说明 |
| :----------- | :---------------------------------------------------- |
| **管理团队** | 选择管理该集成的团队,只有团队成员可以编辑此集成配置 |
| **Endpoint** | 接收回调的 HTTP/HTTPS 地址,必须以 `http://` 或 `https://` 开头 |
| **TLS 验证** | 默认启用。关闭后将跳过目标服务器的 TLS 证书验证,适用于测试环境或自签名证书场景 |
| **Headers** | 自定义请求头,以 Key-Value 形式添加,支持添加多个 |
| **协作空间** | 选择 **全部空间** 或 **部分空间**。选择部分空间时,仅该空间下的告警事件会触发回调 |
| **事件类型** | 勾选需要订阅的事件类型(参见[事件类型](#EventTypes)),支持全选。仅选中的事件类型会触发回调 |
关闭 TLS 证书验证可能存在中间人攻击风险,建议仅在测试环境或使用自签名证书时关闭。
## 四、调用历史
告警 Webhook 提供完整的调用历史记录,方便你排查推送是否成功以及调试回调接口。
### 查看调用历史
进入告警 Webhook 集成详情页,切换到 **调用历史** 页签即可查看。
### 筛选与搜索
| 筛选项 | 说明 |
| :-------- | :----------------------------------------------- |
| **时间范围** | 支持选择最近 1 小时、6 小时、1 天、7 天,或自定义时间范围(最多查看最近 7 天的数据) |
| **告警 ID** | 输入告警 ID 进行精确搜索 |
| **事件类型** | 按事件类型筛选记录 |
| **请求状态** | 按成功或失败筛选 |
### 历史记录字段
| 字段 | 说明 |
| :-------- | :------------------------------ |
| **触发时间** | 事件触发的时间 |
| **事件类型** | 触发的事件类型(如 `a_new`、`a_update` 等) |
| **告警 ID** | 关联的告警 ID,可点击跳转到告警详情 |
| **事件 ID** | 本次回调的唯一标识,可用于去重 |
| **请求状态** | 成功或失败,附带 HTTP 状态码 |
| **耗时** | 请求往返耗时 |
| **请求次数** | 包括首次请求和重试次数 |
### 查看调用详情
点击某条记录的 **查看详情**,可查看完整的请求和响应信息:
* **Request**:包括 Endpoint、Request Headers 和 Request Payload
* **Response**:成功时显示 Response Headers 和 Response Body;失败时显示 Error Message
## 五、常见问题
1. **服务是否有响应超时时间?**
* 服务需要在 2 秒内返回响应,超过 2 秒则认为响应失败
2. **推送失败后是否会持续推送?**
针对特定的网络错误,会进行重试,最多重试1次:
* context deadline exceeded (排除 awaiting headers)
* i/o timeout
* eof
3. **如何保证推送顺序?**
* 理论上同一个告警的事件是按照时间顺序进行推送,但是重试等情况可能会导致乱序
* 服务可以根据 event\_time 进行过滤,如果已经收到了更晚的事件,可以直接过滤掉更早的事件,每一次推送都会携带最新的、完整的信息,偶尔丢失事件是可以容忍的
4. **推送来源可信 IP 白名单?**
* `47.94.95.118`、`123.56.8.183`、`47.94.193.81` 和 `1.13.19.96`(SaaS 版本;私有化部署的推送来源为您自有环境的出口地址,请向您的基础设施团队确认)
* 未来可能会更新,请定期查验
# Webhook 自定义操作
Source: https://docs.flashduty.com/zh/on-call/integration/webhooks/custom-actions
配置自定义操作,当故障发生特定操作时,系统通过 HTTP 回调您配置的地址
配置故障 自定义操作,允许您在故障排查期间,快速调用外部接口,实现故障自愈、信息丰富等任何自定义操作。
## 一、创建操作
1. 登录 Flashduty 控制台,进入【集成中心-Webhook】
2. 点击添加 自定义操作 集成
3. 配置 操作名称,此名称将以按钮的形式体现在故障详情中
4. 配置 协作空间,可以配置多个,但每个协作空间至多添加三个 自定义操作
5. 配置 Endpoint、自定义 Headers
6. 保存,完成
## 二、推送描述
### 请求方式
POST, Content-Type:"application/json"
### 请求 Payload
| 字段 | 类型 | 必含 | 释义 |
| :---------: | :-------------------: | :-: | :----------------------------------- |
| event\_time | int64 | 是 | 事件发生`毫秒时间戳` |
| event\_type | string | 是 | 事件类型,固定值`i_custom` |
| event\_id | string | 是 | 事件 ID,`同一个事件可能因为超时等原因重试多次,接收方需要能够去重` |
| person | [Person](#Person) | 否 | 操作人,仅人为动作时存在 |
| incident | [Incident](#Incident) | 是 | 故障详情 |
**Person**:
| 字段 | 类型 | 必含 | 释义 |
| :----------: | :----: | :-: | :---- |
| person\_id | int64 | 是 | 人员 ID |
| person\_name | string | 是 | 人员名称 |
| email | string | 是 | 邮件地址 |
**Responder**:
| 字段 | 类型 | 必含 | 释义 |
| :--------------: | :----: | :-: | :---- |
| person\_id | int64 | 是 | 人员 ID |
| person\_name | string | 是 | 人员名称 |
| email | string | 是 | 邮件地址 |
| assigned\_at | int64 | 否 | 分派时间 |
| acknowledged\_at | int64 | 否 | 认领时间 |
**Incident**:
| 字段 | 类型 | 必含 | 释义 |
| :----------------: | :------------------------: | :-: | :---------------------------------------------------------------------------------------------------------------------- |
| incident\_id | string | 是 | 故障 ID |
| title | string | 是 | 故障标题 |
| description | string | 否 | 故障描述 |
| impact | string | 否 | 故障影响 |
| root\_cause | string | 否 | 故障根本原因 |
| resolution | string | 否 | 故障解决办法 |
| incident\_severity | string | 是 | 严重程度,枚举值:Critical,Warning,Info |
| incident\_status | string | 是 | 故障状态,枚举值:Critical,Warning,Info,Ok |
| progress | string | 是 | 处理进度,枚举值:Triggered,Processing,Closed |
| created\_at | int64 | 是 | 创建时间 |
| updated\_at | int64 | 是 | 更新时间 |
| start\_time | int64 | 是 | 触发时间,Unix 秒时间戳 |
| last\_time | int64 | 否 | 最新事件时间,关联告警中的最新事件推送时间,Unix 秒时间戳,默认为 0 |
| end\_time | int64 | 否 | 恢复时间,关联的告警全部恢复时,故障也会自动恢复,Unix 秒时间戳,默认为 0 |
| ack\_time | int64 | 否 | 首次认领时间,故障可被多人认领,此时间为最早的认领时间。Unix 秒时间戳,默认为 0 |
| close\_time | int64 | 否 | 关闭时间,end\_time代表故障恢复时间,close\_time代表处理进度的关闭时间,故障恢复时会同时关闭,故障关闭时不影响故障恢复。Unix 秒时间戳,默认为 0 |
| snoozed\_before | int64 | 否 | 暂缓截止时间 |
| labels | map\[string]string | 否 | 标签 KV,Key 和 Value 均为字符串。手动创建时无此信息,自动创建时为聚合的第一条告警的标签信息 |
| fields | map\[string]interface | 否 | 自定义字段 KV,Key 为字符串,Value 可能为任意类型,取决于字段类型 |
| creator | [Person](#Person) | 否 | 创建人员信息,仅手动创建故障时存在 |
| closer | [Person](#Person) | 否 | 关闭人员信息,仅手动关闭故障时存在 |
| responders | \[][Responder](#Responder) | 否 | 处理人员信息列表 |
| alerts | [Alert](#Alert) | 否 | 关联告警 |
| alert\_cnt | int64 | 否 | 关联告警个数 |
| num | string | 是 | 故障短标识,取故障 ObjectID 最后 6 位十六进制并大写,例如 `054D57`,在控制台界面中显示。可作为查询故障详情 API 的替代参数(与 `incident_id` 二选一),同一账号下不唯一,查询时返回最新创建的匹配记录 |
| channel\_id | int64 | 否 | 协作空间ID,为0代表不属于任何空间 |
| channel\_name | string | 否 | 协作空间名称 |
| team\_id | int64 | 否 | 协作空间所属团队 ID,无归属团队时为 0 |
| detail\_url | string | 是 | 详情地址 |
| group\_method | string | 否 | 聚合方式,枚举值:n:不聚合,p:按规则聚合,i:智能聚合 |
**Alert**:
| 字段 | 类型 | 必含 | 释义 |
| :--------------: | :----------------: | :-: | :------------------------------------------------------ |
| alert\_id | string | 是 | 告警 ID |
| data\_source\_id | int64 | 是 | 集成 ID |
| title | string | 是 | 告警标题 |
| description | string | 否 | 告警描述 |
| alert\_key | string | 是 | 告警关联依据 |
| alert\_severity | string | 是 | 严重程度,枚举值:Critical,Warning,Info |
| alert\_status | string | 是 | 告警状态,枚举值:Critical,Warning,Info,Ok |
| progress | string | 是 | 处理进度,枚举值:Triggered,Closed |
| created\_at | int64 | 是 | 创建时间 |
| updated\_at | int64 | 是 | 更新时间 |
| start\_time | int64 | 是 | 首次触发时间(平台接收到的首个事件的时间),Unix 秒时间戳 |
| last\_time | int64 | 是 | 最新事件时间(平台接收到的最新事件时间),Unix 秒时间戳 |
| end\_time | int64 | 否 | 告警恢复时间(平台上一次接收到结束类型事件的时间),Unix 秒时间戳,默认为 0 |
| close\_time | int64 | 否 | 关闭时间,不同于 end\_time,这个是处理进度的关闭,不代表告警真的恢复。Unix 秒时间戳,默认为 0 |
| labels | map\[string]string | 否 | 标签 KV,Key 和 Value 均为字符串 |
### 请求响应
HTTP status code 为 200,认为推送成功。
### 请求示例
```
curl -X POST 'https://example.com/incident/action?a=a' \
-H 'Content-Type: application/json' \
-H 'X-Customize-Header-A: a' \
-d '{
"event_time": 1700208013988,
"event_type": "i_custom",
"incident": {
"event_id":"fac0599a2a25529ba2362c0c184b6cfb",
"account_id": 74058170041504,
"account_name": "头铁科技",
"ack_time": 0,
"alert_cnt": 1,
"alerts": [
{
"account_id": 74058170041504,
"alert_id": "6551f37f8713372ad1054d54",
"alert_key": "asdflasdfl2xzasd112621",
"alert_severity": "Critical",
"alert_status": "Critical",
"close_time": 0,
"created_at": 1699869567,
"data_source_id": 2398086111504,
"description": "cpu.idle < 20%",
"end_time": 0,
"event_cnt": 0,
"labels": {
"a": "a",
"check": "自定义字段测试",
"cluster": "nj",
"metric": "node_cpu_seconds_total",
"resource": "es.nj.01",
"service": "engine",
"v": "v"
},
"last_time": 1699869562,
"progress": "Triggered",
"responder_email": "",
"responder_id": 0,
"responder_name": "",
"start_time": 1699869562,
"title": "nj / es.nj.01 - 自定义字段测试",
"title_rule": "$cluster::$resource::$check",
"updated_at": 1699869576
}
],
"assigned_to": {
"assigned_at": 1699869576,
"escalate_rule_id": "6509344bc1d50d723ca04986",
"escalate_rule_name": "策略5",
"id": "VobpBqvTuXgQ7BZzJ2Qu94",
"layer_idx": 0,
"type": "assign"
},
"channel_id": 1973372625504,
"channel_name": "lim_test",
"close_time": 0,
"created_at": 1699869576,
"data_source_id": 2398086111504,
"dedup_key": "asdflasdfl2xzasd112621",
"description": "cpu.idle < 20%",
"detail_url": "http://10.206.0.17:8567/incident/detail/6551f3888713372ad1054d57",
"end_time": 0,
"equals_md5": "",
"fields": {
"impacted_services": [
"passport",
"order"
],
"priority": "P3"
},
"group_method": "p",
"impact": "",
"incident_id": "6551f3888713372ad1054d57",
"incident_severity": "Critical",
"incident_status": "Critical",
"labels": {
"a": "a",
"check": "自定义字段测试",
"cluster": "nj",
"metric": "node_cpu_seconds_total",
"resource": "es.nj.01",
"service": "engine",
"v": "v"
},
"creator":{
"email":"toutie@flashcat.cloud",
"person_id":1552048792504,
"person_name":"头铁"
},
"last_time": 1699869562,
"num": "054D57",
"progress": "Triggered",
"resolution": "",
"responders": [
{
"acknowledged_at": 0,
"assigned_at": 1699869576,
"email": "zhangsan@toutie.com",
"person_id": 1234648032504,
"person_name": "zhangsan"
}
],
"root_cause": "",
"snoozed_before": 0,
"start_time": 1699869562,
"title": "nj / es.nj.01 - 自定义字段测试",
"updated_at": 1699929113
},
"person": {
"email": "zhangsan@toutie.com",
"person_id": 1999632289504,
"person_name": "zhangsan"
}
}' -v
```
## 三、自定义请求体与值映射
### 自定义请求体
默认情况下,系统会按照上述 [Payload 结构](#请求-payload)推送完整的 JSON 数据。如果您的接收方对数据格式有特殊要求,可以通过**自定义请求体**来重新组织推送内容。
使用 `{{字段路径}}` 语法引用默认 Payload 中的任意字段,系统会在推送时将变量替换为实际值。
**变量语法:**
* 用 `.` 分隔路径层级,如 `{{incident.title}}` 引用故障标题
* 支持数组索引访问,如 `{{incident.responders.0.email}}` 引用第一个处理人的邮箱
* 当整个值只有一个变量时(如 `"{{incident.labels}}"`),会保留原始数据类型(对象、数组、数字等)
* 当变量与其他文本混合时(如 `"故障:{{incident.title}}"`),变量会被转为字符串拼接
**示例:**
```json theme={null}
{
"action": "{{event_type}}",
"incident_id": "{{incident.incident_id}}",
"title": "{{incident.title}}",
"severity": "{{incident.incident_severity}}",
"url": "{{incident.detail_url}}",
"operator": "{{person.person_name}}",
"labels": "{{incident.labels}}"
}
```
如果变量路径在默认 Payload 中不存在,系统会保留原始的 `{{...}}` 文本不做替换。建议先通过测试推送查看实际的默认 Payload,确认可用的字段路径。
### 值映射
通过值映射,可以在自定义请求体的变量解析时自动转换字段值。值映射按**字段路径**分组配置。
**示例:**
```json theme={null}
{
"incident.incident_severity": {
"Critical": "P0",
"Warning": "P1",
"Info": "P2"
}
}
```
配合自定义请求体中的 `"severity": "{{incident.incident_severity}}"` 使用,当故障严重程度为 `Critical` 时,推送结果中 `severity` 字段的值为 `P0`。未匹配到映射的值将保持原样。
## 四、使用场景
### 重启主机
当主机内存或CPU打满,触发主机重启脚本,快速完成主机重启。
### 信息丰富
当故障发生时,回调您的服务,根据告警详情调取 Tracing、Logging、拓扑等信息,主动调用 Flashduty Open API 来更新故障信息,比如增加标签或设定自定义字段,辅助排障。
### 回滚变更
当发生故障时,如果确定故障由变更导致,可以直接触发回调到您的部署平台,开启回滚进程,加速故障恢复。
### 更新 status page
当确定故障影响到线上服务,可以触发外部 status page 更新,及时的通知到您的客户或上下游。
## 五、常见问题
1. **服务是否有响应超时时间?**
* 服务需要在 2 秒内返回响应,超过 2 秒则认为响应失败
2. **推送失败后是否会持续推送?**
针对特定的网络错误,会进行重试,最多重试1次:
* context deadline exceeded (排除 awaiting headers)
* i/o timeout
* eof
2. **推送来源可信 IP 白名单?**
* `47.94.95.118`、`123.56.8.183`、`47.94.193.81` 和 `1.13.19.96`(SaaS 版本;私有化部署的推送来源为您自有环境的出口地址,请向您的基础设施团队确认)
* 未来可能会更新,请定期查验
# 故障 Webhook
Source: https://docs.flashduty.com/zh/on-call/integration/webhooks/incident-webhook
配置故障 Webhook,当故障发生特定操作时,系统通过 HTTP 回调您配置的地址
配置故障 Webhook,当故障发生特定操作(如触发、关闭)时,系统通过 HTTP 回调您配置的地址。回调内容将包含故障最新关键信息,您可以与自研工具进行集成。
## 一、事件类型
目前支持以下事件类型,未来可能会增加。
| 事件类型 | 释义 |
| :------------: | :------------ |
| i\_new | 创建故障(自动或手动创建) |
| i\_assign | 分派故障(自动或手动分派) |
| i\_a\_rspd | 添加处理人 |
| i\_snooze | 手动暂缓故障 |
| i\_wake | 取消暂缓故障 |
| i\_ack | 手动认领故障 |
| i\_unack | 取消认领故障 |
| i\_storm | 触发风暴提醒 |
| i\_custom | 触发自定义操作 |
| i\_rslv | 关闭故障(自动或手动关闭) |
| i\_reopen | 重新打开故障 |
| i\_merge | 手动合并故障 |
| i\_comm | 添加评论 |
| i\_r\_title | 更新故障标题 |
| i\_r\_desc | 更新故障描述 |
| i\_r\_impact | 更新故障影响 |
| i\_r\_rc | 更新故障根因 |
| i\_r\_rsltn | 更新故障解决办法 |
| i\_r\_severity | 更新故障严重程度 |
| i\_r\_field | 更新故障自定义字段 |
## 二、推送描述
### 请求方式
POST, Content-Type:"application/json"
### 请求 Payload
| 字段 | 类型 | 必含 | 释义 |
| :---------: | :-------------------: | :-: | :----------------------------------- |
| event\_time | int64 | 是 | 事件发生`毫秒时间戳` |
| event\_type | string | 是 | 事件类型,枚举值见[事件类型](#EventTypes) |
| event\_id | string | 是 | 事件 ID,`同一个事件可能因为超时等原因重试多次,接收方需要能够去重` |
| person | [Person](#Person) | 否 | 操作人,仅人为动作时存在 |
| incident | [Incident](#Incident) | 是 | 故障详情 |
**Person**:
| 字段 | 类型 | 必含 | 释义 |
| :----------: | :----: | :-: | :---- |
| person\_id | int64 | 是 | 人员 ID |
| person\_name | string | 是 | 人员名称 |
| email | string | 是 | 邮件地址 |
**Responder**:
| 字段 | 类型 | 必含 | 释义 |
| :--------------: | :----: | :-: | :---- |
| person\_id | int64 | 是 | 人员 ID |
| person\_name | string | 是 | 人员名称 |
| email | string | 是 | 邮件地址 |
| assigned\_at | int64 | 否 | 分派时间 |
| acknowledged\_at | int64 | 否 | 认领时间 |
**Incident**:
| 字段 | 类型 | 必含 | 释义 |
| :----------------: | :------------------------: | :-: | :---------------------------------------------------------------------------------------------------------------------- |
| incident\_id | string | 是 | 故障 ID |
| title | string | 是 | 故障标题 |
| description | string | 否 | 故障描述 |
| impact | string | 否 | 故障影响 |
| root\_cause | string | 否 | 故障根本原因 |
| resolution | string | 否 | 故障解决办法 |
| incident\_severity | string | 是 | 严重程度,枚举值:Critical,Warning,Info |
| incident\_status | string | 是 | 故障状态,枚举值:Critical,Warning,Info,Ok |
| progress | string | 是 | 处理进度,枚举值:Triggered,Processing,Closed |
| created\_at | int64 | 是 | 创建时间 |
| updated\_at | int64 | 是 | 更新时间 |
| start\_time | int64 | 是 | 触发时间,Unix 秒时间戳 |
| last\_time | int64 | 否 | 最新事件时间,关联告警中的最新事件推送时间,Unix 秒时间戳,默认为 0 |
| end\_time | int64 | 否 | 恢复时间,关联的告警全部恢复时,故障也会自动恢复,Unix 秒时间戳,默认为 0 |
| ack\_time | int64 | 否 | 首次认领时间,故障可被多人认领,此时间为最早的认领时间。Unix 秒时间戳,默认为 0 |
| close\_time | int64 | 否 | 关闭时间,end\_time代表故障恢复时间,close\_time代表处理进度的关闭时间,故障恢复时会同时关闭,故障关闭时不影响故障恢复。Unix 秒时间戳,默认为 0 |
| snoozed\_before | int64 | 否 | 暂缓截止时间 |
| labels | map\[string]string | 否 | 标签 KV,Key 和 Value 均为字符串。手动创建时无此信息,自动创建时为聚合的第一条告警的标签信息 |
| fields | map\[string]interface | 否 | 自定义字段 KV,Key 为字符串,Value 可能为任意类型,取决于字段类型 |
| creator | [Person](#Person) | 否 | 创建人员信息,仅手动创建故障时存在 |
| closer | [Person](#Person) | 否 | 关闭人员信息,仅手动关闭故障时存在 |
| responders | \[][Responder](#Responder) | 否 | 处理人员信息列表,仅故障被分派后存在。对于i\_new事件,此值可能为空 |
| alert\_cnt | int64 | 否 | 关联告警个数 |
| num | string | 是 | 故障短标识,取故障 ObjectID 最后 6 位十六进制并大写,例如 `56E25B`,在控制台界面中显示。可作为查询故障详情 API 的替代参数(与 `incident_id` 二选一),同一账号下不唯一,查询时返回最新创建的匹配记录 |
| channel\_id | int64 | 否 | 协作空间ID,为0代表不属于任何空间 |
| channel\_name | string | 否 | 协作空间名称 |
| team\_id | int64 | 否 | 协作空间所属团队 ID,无归属团队时为 0 |
| detail\_url | string | 是 | 详情地址 |
| group\_method | string | 否 | 聚合方式,枚举值:n:不聚合,p:按规则聚合,i:智能聚合 |
### 请求响应
HTTP status code 为 200,认为推送成功。
### 请求示例
```
curl -X POST 'https://example.com/incident/webhook?a=a' \
-H 'Content-Type: application/json' \
-H 'X-Customize-Header-A: a' \
-d '{
"event_id":"fac0599a2a25529ba2362c0c184b6cfb",
"event_time":1689335086948,
"event_type":"i_new",
"incident":{
"account_id":74058170041504,
"account_name":"头铁科技kk",
"ack_time":0,
"alert_cnt":0,
"assigned_to":{
"assigned_at":1689335086,
"escalate_rule_id":"64abb8a687e7984845822139",
"escalate_rule_name":"默认分派",
"id":"NBRbNwDSTSMijKXdLtBU3T",
"layer_idx":0,
"type":"assign"
},
"channel_id":1840312623504,
"channel_name":"Reduce Noise",
"close_time":0,
"created_at":1689335086,
"creator":{
"email":"toutie@flashcat.cloud",
"person_id":1552048792504,
"person_name":"头铁"
},
"creator_id":1552048792504,
"data_source_id":0,
"dedup_key":"",
"description":"",
"detail_url":"http://10.206.0.17:8567/incident/detail/64b1352e376e32c85c56e25b",
"end_time":0,
"equals_md5":"",
"group_method":"n",
"impact":"",
"incident_id":"64b1352e376e32c85c56e25b",
"incident_severity":"Critical",
"incident_status":"Critical",
"labels":{
"check": "cpu idle low"
},
"last_time":1689335086,
"num":"56E25B",
"progress":"Triggered",
"resolution":"",
"responder_ids":[
1552048792504
],
"responders":[
{
"acknowledged_at":0,
"assigned_at":1689335086,
"email":"toutie@flashcat.cloud",
"person_id":1552048792504,
"person_name":"头铁"
}
],
"root_cause":"",
"snoozed_before":0,
"start_time":1689335086,
"title":"ysy028",
"updated_at":1689335086
},
"person":{
"email":"toutie@flashcat.cloud",
"person_id":1552048792504,
"person_name":"头铁"
}
}' -v
```
## 三、配置指南
进入 **集成中心** → **Webhook** → 添加或编辑 **故障 Webhook** 集成。
### 基础设置
填写集成名称和描述,便于后续管理。
### Webhook 设置
| 配置项 | 说明 |
| :----------- | :---------------------------------------------------- |
| **Endpoint** | 接收回调的 HTTP/HTTPS 地址,必须以 `http://` 或 `https://` 开头 |
| **TLS 验证** | 默认启用。关闭后将跳过目标服务器的 TLS 证书验证,适用于测试环境或自签名证书场景 |
| **Headers** | 自定义请求头,以 Key-Value 形式添加,支持添加多个 |
| **协作空间** | 选择 **全部空间** 或 **部分空间**。选择部分空间时,仅该空间下的故障事件会触发回调 |
| **事件类型** | 勾选需要订阅的事件类型(参见[事件类型](#EventTypes)),支持全选。仅选中的事件类型会触发回调 |
关闭 TLS 证书验证可能存在中间人攻击风险,建议仅在测试环境或使用自签名证书时关闭。
### 自定义请求体
默认情况下,系统会按照上述 [Payload 结构](#请求-payload)推送完整的 JSON 数据。如果你的接收方对数据格式有特殊要求,可以通过**自定义请求体**来重新组织推送内容。
使用 `{{字段路径}}` 语法引用默认 Payload 中的任意字段,系统会在推送时将变量替换为实际值。
**变量语法:**
* 用 `.` 分隔路径层级,如 `{{incident.title}}` 引用故障标题
* 支持数组索引访问,如 `{{incident.responders.0.email}}` 引用第一个处理人的邮箱
* 当整个值只有一个变量时(如 `"{{incident.labels}}"`),会保留原始数据类型(对象、数组、数字等)
* 当变量与其他文本混合时(如 `"故障:{{incident.title}}"`),变量会被转为字符串拼接
**示例:**
将默认 Payload 转为自定义格式推送到企业内部系统:
```json theme={null}
{
"msg_type": "incident",
"event": "{{event_type}}",
"content": {
"id": "{{incident.incident_id}}",
"name": "{{incident.title}}",
"severity": "{{incident.incident_severity}}",
"status": "{{incident.progress}}",
"channel": "{{incident.channel_name}}",
"url": "{{incident.detail_url}}",
"labels": "{{incident.labels}}",
"responders": "{{incident.responders}}"
}
}
```
如果变量路径在默认 Payload 中不存在,系统会保留原始的 `{{...}}` 文本不做替换。建议先通过调用历史查看实际推送的默认 Payload,确认可用的字段路径。
### 值映射
在自定义请求体中,您可能需要将 Flashduty 的字段值转换为接收方系统所期望的格式。通过 **值映射** 可以在变量解析时自动完成值的转换。
值映射按**字段路径**分组配置,每个路径下是一个 `源值 → 目标值` 的映射表。
**示例:**
将严重程度和处理进度转换为接收方系统的自定义值:
```json theme={null}
{
"incident.incident_severity": {
"Critical": "P0",
"Warning": "P1",
"Info": "P2"
},
"incident.progress": {
"Triggered": "open",
"Processing": "in_progress",
"Closed": "resolved"
}
}
```
配合如下自定义请求体使用:
```json theme={null}
{
"severity": "{{incident.incident_severity}}",
"status": "{{incident.progress}}",
"title": "{{incident.title}}"
}
```
当故障严重程度为 `Critical` 时,推送结果中 `severity` 字段的值为 `P0`。未匹配到映射的值将保持原样。
## 四、调用历史
故障 Webhook 提供完整的调用历史记录,方便你排查推送是否成功以及调试回调接口。
### 查看调用历史
进入故障 Webhook 集成详情页,切换到 **调用历史** 页签即可查看。
### 筛选与搜索
| 筛选项 | 说明 |
| :-------- | :----------------------------------------------- |
| **时间范围** | 支持选择最近 1 小时、6 小时、1 天、7 天,或自定义时间范围(最多查看最近 7 天的数据) |
| **故障 ID** | 输入故障 ID 进行精确搜索 |
| **事件类型** | 按事件类型筛选记录 |
| **请求状态** | 按成功或失败筛选 |
### 历史记录字段
| 字段 | 说明 |
| :-------- | :--------------------------- |
| **触发时间** | 事件触发的时间 |
| **事件类型** | 触发的事件类型(如 `i_new`、`i_ack` 等) |
| **故障 ID** | 关联的故障 ID,可点击跳转到故障详情 |
| **事件 ID** | 本次回调的唯一标识,可用于去重 |
| **请求状态** | 成功或失败,附带 HTTP 状态码 |
| **耗时** | 请求往返耗时 |
| **请求次数** | 包括首次请求和重试次数 |
### 查看调用详情
点击某条记录的 **查看详情**,可查看完整的请求和响应信息:
* **Request**:包括 Endpoint、Request Headers 和 Request Payload
* **Response**:成功时显示 Response Headers 和 Response Body;失败时显示 Error Message
## 五、常见问题
1. **服务是否有响应超时时间?**
* 服务需要在 2 秒内返回响应,超过 2 秒则认为响应失败
2. **推送失败后是否会持续推送?**
针对特定的网络错误,会进行重试,最多重试1次:
* context deadline exceeded (排除 awaiting headers)
* i/o timeout
* eof
3. **如何保证推送顺序?**
* 理论上同一个故障的事件是按照时间顺序进行推送,但是重试等情况可能会导致乱序
* 服务可以根据 event\_time 进行过滤,如果已经收到了更晚的事件,可以直接过滤掉更早的事件,每一次推送都会携带最新的、完整的信息,偶尔丢失事件是可以容忍的
4. **推送来源可信 IP 白名单?**
* `47.94.95.118`、`123.56.8.183`、`47.94.193.81` 和 `1.13.19.96`(SaaS 版本;私有化部署的推送来源为您自有环境的出口地址,请向您的基础设施团队确认)
* 未来可能会更新,请定期查验
# Jira 同步
Source: https://docs.flashduty.com/zh/on-call/integration/webhooks/jira-sync
通过 Jira 同步 Webhook,实现故障与 Jira Issue 的关联。
**版本要求**:此功能需要 On-call 专业版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/)
通过 Jira 同步 Webhook,将 Flashduty 的故障与 Jira Issue 进行关联同步,实现 Flashduty 与 Jira 的联动。
## 前提说明
* 该集成兼容 Jira Cloud 以及 Jira Server 和 Jira Data Center 的 7.x 和 8.x 版本。
* 目前仅支持将故障相关信息或状态单向同步到 Jira 中,Jira 中的信息不会同步到 Flashduty 中。
* 对于 Jira Cloud,请在授权配置的密码处填写 API Token;而对于Jira Server 或 Data Center,则使用您的 Jira 账户登录密码即可。
## 在 Jira Cloud 中获取 API Token (Jira Server 和 Data Center 请跳过)
* 登录 Jira Cloud 后,点击右上角头像,选择 **管理账户**。
* 在 **管理账户** 页面中,选择 **安全性** 选项卡。
* 在 **安全性** 页面中,点击 **创建并管理 API 令牌** 按钮。
* 在 **创建并管理 API 令牌** 弹窗中,填写 API token 名称,并选择过期时间。
* 点击 **创建** 按钮,创建 API token。
* 创建完成后,复制 API token 值,并粘贴到 Flashduty 授权配置中的 API 令牌处。
## 在 Flashduty On-call 中配置集成
### 1. 创建并认证 Jira 集成
在集成中心,选择 **Webhook** ,选择 **Jira 同步** 集成,并填写以下认证信息。
* **Jira 平台类型**:根据您使用的版本进行选择,如果是 Data Center 版本的请选择私有化(Server) 即可。
* **服务地址**:Cloud 版本请填写您的实际访问地址,例如: [https://your-domain.atlassian.net,Server](https://your-domain.atlassian.net,Server) 版本请填写您的服务访问地址,例如: [https://your-jira-server-url.com。](https://your-jira-server-url.com。)
* **用户名**:您的 Jira 账户名,Cloud 版本请填写您的邮箱,Server 版本请填写您的 Jira 账户名。
* **API令牌/密码**:您的 Jira 账户密码,Cloud 版本请填写 API Token,Server 版本请填写您的 Jira 账户密码。
* 填写完成后,点击 **下一步** 按钮,进行相关配置。
**关于权限**:请确保您的 Jira 账户拥有获取相关项目、事务类型以及创建 Issue 等权限,建议使用管理员账户。
### 2. Jira 集成配置
* **集成名称**:为当前集成定义一个名称。
* **管理团队**:选择管理该集成的团队,只有团队成员可以编辑此集成配置。
* **触发模式**:
* 自动触发:需要配置相应的条件,Flashduty On-call 会自动将符合条件的故障同步到 Jira 中。
* 手动触发:需要在故障详情页的更多操作中手动触发 Jira 同步(该集成配置的名称为触发器名称)。
* **项目 ID**:选择需要同步至 Jira 的项目。
* **事务类型**:选择需要同步至 Jira 的事务类型。
* **协作空间**:选择该集成生效的协作空间,只有该协作空间内的故障才可以同步至 Jira 中。
* **严重程度映射**:如果选择的事务类型不支持优先级字段,则无法配置该映射关系。
* **自定义字段映射**:可以选择将故障的某些标签或所有标签以及自定义字段内容同步至 Jira 的字段中(仅支持文本类型的字段)。
### 3. 关于更新
* 已经创建 Issue 的故障,如果您更新了故障的严重程度、状态,Jira 中会自动更新,但 Jira 中的更新不会同步到 Flashduty 中。
* 评论信息会同步到 Jira 中,但 Jira 中更新的内容不会同步到 Flashduty 中。
* 更新故障中的标题、描述、标签等字段的信息,Jira 中不会更新。
### 4. Flashduty 与 Jira 的映射关系
#### 字段映射
| Jira | Flashduty |
| ---- | --------- |
| 摘要 | 标题 |
| 描述 | 描述 |
| 优先级 | 严重程度 |
| 报告人 | 集成配置的用户 |
| 评论 | 评论 |
#### 状态映射
| Jira | Flashduty |
| ----------- | --------- |
| Todo | 待处理 |
| In Progress | 处理中 |
| Done | 已解决 |
### 5. 注意事项
* Flashduty On-call 会按照默认的字段映射以及您配置的自定义字段映射进行同步信息,如果您的 Jira 事务类型中有必选的字段且没有配置映射关系,则会遇到创建 Jira Issue 失败的情况。
* Jira 的 Issue 详情是基于项目 KEY + 编号的格式进行访问的,如果您修改了项目 KEY,可能无法通过 Flashduty 中保存的 Issue 地址进行访问,请谨慎修改项目 KEY。
# ServiceDesk Plus 同步
Source: https://docs.flashduty.com/zh/on-call/integration/webhooks/servicedesk-plus-sync
通过 ServiceDesk Plus 同步 Webhook,实现故障与 ServiceDesk Plus request 的关联。
**版本要求**:此功能需要 On-call 专业版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/)
通过 ServiceDesk Plus 同步 Webhook,将 Flashduty 的故障与 ServiceDesk Plus request 进行关联同步,实现 Flashduty 与 ServiceDesk Plus 的联动。
本集成基于 ServiceDesk Plus 官方提供的 v3 API 协议,兼容其接口规范。若您使用私有化部署版本,请确认其 API 是否支持 v3 版本。此外,ServiceDesk Plus 的云版本与私有化版本在授权配置方式上存在差异,具体配置请参考相关文档说明。
* [云版本](#云版本)
* [私有化](#私有化)
在配置此集成时,如果您选择的同步方向是 From\_ServiceDesk\_Plus,您可以直接跳过授权相关配置,直接参考[配置同步](#配置同步)即可。
## 云版本
### 在 ServiceDesk Plus
#### 步骤1 创建授权应用
请根据您的 ServiceDesk Plus 服务区域选择对应的 Developer Console 地址:[Data Centres](https://www.manageengine.com/products/service-desk/sdpod-v3-api/getting-started/data-centers.html)
1. 登录 Developer Console,选择 `Self Client` 类型的 Client 并创建。
2. 点击 `Generate Code`,在 `Scope` 中填写:**SDPOnDemand.requests.ALL,SDPOnDemand.setup.READ,SDPOnDemand.custommodule.READ**。权限范围参考[官方文档](https://www.manageengine.com/products/service-desk/sdpod-v3-api/getting-started/oauth-2.0.html#scopes)。
3. `Time Duration` 选择最大的 **10 minutes**,`Scope Description` 填写内容可自定义,比如: Flashduty 同步使用,并创建。
4. 将生成的 **Code** 和 **Client ID** 以及 **Client Secret** 复制备用。


###### 注意:Code 的有效期只有 10 分钟且只能使用一次,所以在获取到 Code 后,请在有效期内尽快完成[集成授权](#集成授权)
### 在 Flashduty On-call
#### 步骤2 集成授权
请根据您的 ServiceDesk Plus 服务区域选择对应的 API Endpoint 和 Accounts Server URL:[Data Centres](https://www.manageengine.com/products/service-desk/sdpod-v3-api/getting-started/data-centers.html)
1. `平台类型` 选择**云版本**,填写`API Endpoint` 和 `Accounts Server URL`。
2. 将**创建授权应用**步骤中生成的 `Code` 和 `Client ID` 以及 `Client Secret` 填写到对应的编辑框并点击下一步完成[集成配置](#集成配置)(如果报错请重新获取 Code,或联系技术支持排查问题)。
## 私有化版本
### 在 ServiceDesk Plus
#### 步骤1 生成 API 密钥
1. 登录 ServiceDesk Plus 控制台,在个人中心点击 `生成 API 密钥`。
2. `令牌过期时间` 选择 **永不过期**,将生成的 **Token** 复制备用,并完成[集成授权](#私有化版本集成授权)。
###### 注意:生成 API 密钥的用户需要具备相关权限,比如创建/更新请求、获取模版/优先级/自定义字段列表等权限,如果权限不足,会导致无法完成集成配置,建议使用管理员角色生成。
### 在 Flashduty On-call
#### 步骤2 集成授权
1. `平台类型` 选择**私有化版本**,填写`API Endpoint`。
2. 将生成的 **Token** 填写到对应的编辑框并点击下一步完成[集成配置](#集成配置)。
## 通用配置
### 在 Flashduty On-call
#### 步骤1 集成配置
1. **集成名称:** 为当前集成定义一个名称。
2. **管理团队:** 当选择管理团队后,只有该团队成员以及租户管理员可以编辑此集成。
3. **同步方向:**
* To\_ServiceDesk\_Plus:将 Flashduty 的故障同步至 ServiceDesk Plus。
* From\_ServiceDesk\_Plus:将 ServiceDesk Plus 的 Request 同步至 Flashduty。
* Two-way:Flashduty 和 ServiceDesk Plus 互相同步。
4. **触发模式**:
* 自动触发:需要配置相应的条件,Flashduty On-call 会自动将符合条件的故障同步到 ServiceDesk Plus 中。
* 手动触发:需要在故障详情页的更多操作中手动触发 ServiceDesk Plus 同步(该集成配置的名称为触发器名称)。
5. **协作空间**:选择该集成生效的协作空间。
6. **请求模版**:选择创建 request 时使用的模版,为空时使用默认模版创建工单。
7. **严重程度映射**:可以选择使用严重程度、故障标签、自定义字段的值与 ServiceDesk Plus 的优先级字段进行映射,如果为空,在创建工单时不传该字段。
8. **自定义字段映射**:可以将故障中的标签或自定义字段,映射到 ServiceDesk Plus 工单中的对应文本字段,实现信息自动填充。该功能支持将常见上下文信息(如服务名、实例地址、指标名称等)同步至 ServiceDesk Plus,便于后续排查与跟踪。
* 仅支持目标为单行文本或多行文本类型的字段。
* 支持从故障标签(如 service、instance)或自定义属性中提取值。
* 若源字段为空,目标字段也将保持为空,不会覆盖原有内容。
9. **指派对象映射**:当 Flashduty 的故障同步至 ServiceDesk Plus 并需要自动指派到 Technician 或 Group 时,可以获取 Flashduty 故障标签的值作为指派对象(如果对应的指派对象不存在,会导致同步失败,请谨慎选择)。
10. **请求者**:创建工单时指定的 requester,如果工单在创建时该字段是必须,则需要配置。
11. 点击`保存`完成配置。
### 在 ServiceDesk Plus
#### 步骤2 配置同步
要实现 ServiceDesk Plus 的 Request 向 Flashduty 的同步,请参考此配置项。**注意:** 不同版本的路径可能略有不同,但配置方法相同。
##### 创建 Webhook
1. 登录 ServiceDesk Plus 控制台,找到 `Setup` 配置页面。
2. 选择 `Automation` 之后,进入到 `Custom Actions` 页面,并选择 `Webhooks`。
3. 点击 `New Webhook`,在编辑页面中 `Webhook Name` 填写 **to\_Flashduty**。
4. `URL` 填写集成的推送地址 。
5. `Applies to` 选择 **Requsts**,`Method` 选择 **POST**,`Headers` 中填写 **Content-Type application/json**。
6. `Message Body` 的 Type 选择 **JSON**,并填写以下内容:
```
# 云版本
{
"subject":"${subject}",
"request_id":"${id}",
"description":"${udf_fields.txt_destination}",
"priority":"${priority.name}",
"status":"${status.name}",
"txt_test_field":"${udf_fields.txt_test_field}"
}
```
```
# 私有化版本
{
"suject":"${{request.subject}}",
"request_id":"${{request.id}}",
"description":"${{request.description}}",
"status":"${{request.status.name}}",
"priority":"${{request.priority.name}}",
"udf_sline_301":"${{request.udf_fields.udf_sline_301}}"
}
```
7. 点击 `Save` 完成配置。

##### 步骤3 创建触发器
1. 登录 ServiceDesk Plus 控制台,找到 `Setup` 配置页面。
2. 选择 `Automation` 之后,进入到 `Triggers` 页面,并选择 `Request`。
3. 点击 `New Trigger`,在编辑页面中 `Name` 填写 **to\_Flashduty**。
4. `Trigger applies to` 选择 **Request**,`Execute when a request is` 勾选 **Create 和 Edited**。
5. `Execute during` 选择 **Any time**,并勾选 **Enable Trigger**。
6. `Conditions` 选择 `Without condition` 或按实际需求配置。
7. 在 `Actions` 中选择 **Webhook** 并勾选 **to\_Flashduty** 通道。
8. 点击 `Save` 完成配置。

## 同步信息映射关系
### 表单字段
| ServiceDesk Plus | Flashduty | 备注 |
| ---------------- | ------------- | ----- |
| Subject | Title | 标题 |
| Description | Description | 描述信息 |
| Status | Progress | 状态 |
| Priority | Severity | 严重程度 |
| Others | Custom Fields | 自定义字段 |
### 状态映射
| ServiceDesk Plus | Flashduty | 备注 |
| -------------------- | ---------- | --------- |
| Open | Triggered | 触发 |
| In Progress | Processing | 待处理 |
| Assigned | Processing | 待处理 |
| Pending Verification | Processing | 待处理 |
| Staging | Processing | 待处理 |
| On Hold | Snoozed | 默认暂缓 2 小时 |
| Resolved | Closed | 关闭 |
| Closed | Closed | 关闭 |
| Canceled | Closed | 关闭 |
| Rejected | Closed | 关闭 |
## 调用历史
ServiceDesk Plus 同步集成提供完整的调用历史记录,方便你排查同步是否成功以及调试接口问题。
### 查看调用历史
进入 ServiceDesk Plus 同步集成详情页,切换到 **调用历史** 页签即可查看。
### 筛选与搜索
| 筛选项 | 说明 |
| :-------- | :----------------------------------------------- |
| **时间范围** | 支持选择最近 30 分钟、6 小时、1 天、2 天、7 天、14 天、30 天,或自定义时间范围 |
| **故障 ID** | 输入故障 ID 进行精确搜索 |
| **协作空间** | 按协作空间筛选记录 |
| **请求状态** | 按成功或失败筛选 |
### 历史记录字段
| 字段 | 说明 |
| :------------- | :---------------------------------------------------- |
| **触发时间** | 事件触发的时间 |
| **故障标题** | 关联的故障标题,可点击跳转到故障详情 |
| **Request ID** | ServiceDesk Plus 工单 ID,可点击跳转到 ServiceDesk Plus 查看工单详情 |
| **协作空间** | 关联的协作空间,可点击跳转 |
| **请求状态** | 成功或失败 |
### 查看调用详情
点击某条记录的 **查看详情**,可查看完整的请求信息:
* **故障 ID**:关联的故障 ID
* **协作空间**:关联的协作空间
* **故障标题**:可点击跳转到故障详情页
* **触发时间**:请求触发的时间
* **请求状态**:成功或失败
* **Error Message**:失败时显示错误信息
## 常见问题
Scope 是否可以更改
不可以,目前所使用的 Scope 已经是最小单元了,Flashduty 在与 ServiceDesc Plus 进行同步 request 时,需要做获取/创建/更新操作,以及在配置集成时,需要获取优先级/自定义字段列表,所以需要相应的权限支持。
# ServiceNow 同步
Source: https://docs.flashduty.com/zh/on-call/integration/webhooks/servicenow-sync
通过 ServiceNow 同步 Webhook,实现故障与 ServiceNow Incident 的关联。
**版本要求**:此功能需要 On-call 专业版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/)
通过 ServiceNow 同步 Webhook,将 Flashduty 的故障与 ServiceNow Incident 进行关联同步,实现 Flashduty 与 ServiceNow 的联动。
## 在 ServiceNow
### 创建用户
需创建一个用户以连接 ServiceNow 实例,用于 Incident 的同步与更新。如果已有可用用户,请直接跳过本步骤。
1. 登录 ServiceNow 实例控制台,通过选择 `ALL` ,输入 `USERS` 选择`Organization`-`Users` 。
2. 点击 `New` 新建用户。
3. 在编辑页面中,`User ID` 输入:flashduty 。
4. `Password needs reset` 和 `Web service access only` 以及 `Internal Integration User` 保持取消勾选状态。
5. 提交保存。

### 配置用户
> **用户角色说明**
> **itil:** 该角色在 Flashduty 中的主要使用范围仅限于在同步 ServiceNow Incident 时,进行获取、创建、更新 ServiceNow Incident,不涉及其他任何操作。
>
> **personalize\_dictionary:** 该角色在 Flashduty 中的主要使用范围仅限于 ServiceNow Incident Table 的字段获取,不涉及其他任何操作。
>
> 关于以上两个角色更多权限范围,可以参考 ServiceNow [官方文档](https://www.servicenow.com/docs/bundle/washingtondc-platform-administration/page/administer/roles/reference/r_BaseSystemRoles.html#d130465e3182)
1. 在用户列表页面,找到新创建的 `flashduty` 用户并进到配置页面。
2. 在编辑页面中,点击 `Set Password` 设置一个密码。
3. 点击 `Roles` 添加 **personalize\_dictionary 和 itil** 角色(如果不需要配置自定义字段映射关系,可以不授予 personalize\_dictionary 权限)。
4. 点击 `Update` 更新配置。


## 在 Flashduty On-call
### 配置集成
将以上配置的用户名/密码以及实例名称输入到左侧集成信息中并点击下一步进行配置。
1. **集成名称:** 为当前集成定义一个名称。
2. **管理团队:** 当选择管理团队后,只有该团队成员以及租户管理员可以编辑此集成。
3. **协作空间**:选择该集成生效的协作空间,。
4. **同步方向:**
* To\_ServiceNow:将 Flashduty 的故障同步至 ServiceNow。
* From\_ServiceNow:将 ServiceNow 的 Incident 同步至 Flashduty。
* Two-way:Flashduty 和 ServiceNow 互相同步。
5. **触发模式**:
* 自动触发:需要配置相应的条件,Flashduty On-call 会自动将符合条件的故障同步到 ServiceNow 中。
* 手动触发:需要在故障详情页的更多操作中手动触发 ServiceNow 同步(该集成配置的名称为触发器名称)。
6. **严重程度映射**:
* ServiceNow 的 Priority 是由 Impact 和 Urgency 的值共同决定的,所以可以参考 ServiceNow 的 `Priority Lookup Rules` 进行配置。
* 当 ServiceNow Incident 的 Urgency 发生变化时,才会触发 Flashduty 故障严重程度的更新。
* 由于 Flashduty 在遵循最小权限的情况下,无法获取 ServiceNow 的 Impact 和 Urgency 列表,所以只提供了默认值,如果您需要自定义映射关系时,可以联系技术支持。
7. **自定义字段映射**:可以将故障中的标签或自定义字段,映射到 ServiceNow 工单中的对应文本字段,实现信息自动填充。该功能支持将常见上下文信息(如服务名、实例地址、指标名称等)同步至 ServiceNow,便于后续排查与跟踪。
* 仅支持目标为单行文本或多行文本类型的字段。
* 支持从故障标签(如 service、instance)或自定义属性中提取值。
* 若源字段为空,目标字段也将保持为空,不会覆盖原有内容。
* 映射配置在集成设置中统一管理,无需每次手动填写。
## 在 ServiceNow
当同步方向选择 From\_ServiceNow 或 Two-way 时,还需要在 ServiceNow 中做相应的配置,以便将 ServiceNow Incident 同步至 Flashduty, 在同步至 Flashduty 时,有以下两种方式,可根据实际需求选择即可。
### 手动同步
该方式依赖 ServiceNow 提供的 UI Action 和 Script Include 的配置,根据以下步骤配置完成的效果:当新建 Incident 或更新 Incident 时,可以在功能区看到发送同步请求的按钮,触发该按钮,可以将当前 Incident 的内容同步至 Flashduty。需要注意的是,如果触发请求时遇到失败的情况,请重试(重试时间间隔需大于 10 秒)。
#### 配置 UI Action
1. 登录 ServiceNow 实例控制台,通过选择 `ALL` ,输入 `UI Actions` 选择`System Definition`-`UI Actions` 。
2. 点击 `New` 新建 Action。
3. `Name` 输入: **Send To Flashduty**, `Table` 选择 **Incident** 。
4. `Form button` ,`Active` ,`Show insert` ,`Show update` ,`Client`, `List v2/3 Compatible` 保持勾选状态。
5. `Onclick` 输入:**onClick();**。
6. `Script` 输入:
```js theme={null}
function onClick() {
g_form.save();
var ga = new GlideAjax("IncidentWebhookHelperAjax");
ga.addParam("sysparm_name", "sendWebhook");
ga.addParam("sysparm_sys_id", g_form.getUniqueValue());
ga.getXMLAnswer(function (response) {
alert("Webhook Triggered: " + response);
});
}
```
7. 提交保存。
#### 配置 Script Include
1. 登录 ServiceNow 实例控制台,通过选择 `ALL` ,输入 `Script Includes` 选择`System Definition`-`Script Includes` 。
2. 点击 `New` 新建 Script Include。
3. `Name` 输入:**IncidentWebhookHelper** , `Accessible from` 选择 **All application scopes**。
4. `Client callable` 和 `Active` 保持勾选状态。
5. `Script` 输入以下内容,其中 **request.setEndpoint** 中需要补充集成的推送地址 :
注意: body 中配置的是默认接收字段,如果有自定义字段需要同步至 Flashduty ,需要额外手动补充内容到 body 中,比如希望添加一个字段名为:test\_001 的字段(该字段名可以在配置集成中添加自定义字段的时候获取,不要使用 ServiceNow Inident 表单中显示的字段名),那么需要在 body 中补充:test\_001: current.getDisplayValue("test\_001")。
```js theme={null}
var IncidentWebhookHelper = Class.create();
IncidentWebhookHelper.prototype = {
initialize: function() {},
sendIncidentWebhook: function(current) {
function getLastComment(sysId) {
var journalGR = new GlideRecord('sys_journal_field');
journalGR.addQuery('element_id', sysId);
journalGR.addQuery('element', 'comments');
journalGR.orderByDesc('sys_created_on');
journalGR.setLimit(1);
journalGR.query();
if (journalGR.next()) {
return journalGR.getValue('value');
}
return '';
}
var body = {
action_type: current.isNewRecord() ? 'insert' : 'update',
number: current.getValue("number"),
sys_id: current.getUniqueValue(),
short_description: current.getValue("short_description"),
description: current.getValue("description"),
impact: current.getDisplayValue("impact"),
urgency: current.getDisplayValue("urgency"),
comments: getLastComment(current.getUniqueValue()),
{original.key}: current.getDisplayValue("{original.key}")
};
try {
var request = new sn_ws.RESTMessageV2();
request.setHttpMethod("POST");
request.setEndpoint("PUSH URL");
request.setRequestHeader("Content-Type", "application/json");
request.setRequestBody(JSON.stringify(body));
request.executeAsync();
} catch (ex) {
gs.error("Webhook Call failed: " + ex.message);
}
},
type: 'IncidentWebhookHelper'
};
```
6. 提交保存。
7. 回到 Script Includes 列表,继续创建。
8. 点击 `New` 新建 Script Include。
9. `Name` 输入:**IncidentWebhookHelperAjax** , `Accessible from` 选择 **All application scopes**。
10. `Client callable` 和 `Active` 保持勾选状态。
11. `Script` 输入以下内容:
```js theme={null}
var IncidentWebhookHelperAjax = Class.create();
IncidentWebhookHelperAjax.prototype = Object.extendsObject(
global.AbstractAjaxProcessor,
{
sendWebhook: function () {
var sysId = this.getParameter("sysparm_sys_id");
var gr = new GlideRecord("incident");
if (gr.get(sysId)) {
var helper = new IncidentWebhookHelper();
helper.sendIncidentWebhook(gr);
return "Success";
}
return "Request failed";
},
}
);
```
12. 提交保存。
### 自动同步
该方式依赖 ServiceNow 提供的 Business Rules 的配置,使用该方式可以实现当有新建或更新事件时,自动将 Incident 同步至 Flashduty。
#### 配置 Business Rules
1. 登录 ServiceNow 实例控制台,通过选择 `ALL` ,输入 `Business Rules` 选择`System Definition`-`Business Rules` 。
2. 点击 `New` 新建 Business Rule。
3. `Name` 输入:**Send To Flashduty** , `Table` 选择 **Incident**。
4. `Advanced` 和 `Active` 保持勾选状态。
5. 在 `When to run` 区域中,`When` 选择 **async**,`Insert` 和 `Upsert` 保持勾选状态,其他按需配置。
6. 在 `Advanced` 区域中,`Script` 填写以下内容,其中 **endpoint** 中需要补充集成的推送地址
注意: body 中配置的是默认接收字段,如果有自定义字段需要同步至 Flashduty ,需要额外手动补充内容到 body 中,比如希望添加一个字段名为:test\_001 的字段(该字段名可以在配置集成中添加自定义字段的时候获取,不要使用 ServiceNow Inident 表单中显示的字段名),那么需要在 body 中补充:test\_001: current.getDisplayValue("test\_001")。
```js theme={null}
(function executeRule(current, previous) {
function getLastComment(recordSysId) {
var journalGR = new GlideRecord("sys_journal_field");
journalGR.addQuery("element_id", recordSysId);
journalGR.addQuery("element", "comments");
journalGR.orderByDesc("sys_created_on");
journalGR.setLimit(1);
journalGR.query();
if (journalGR.next()) {
var comment = journalGR.getValue("value");
return comment;
}
return "";
}
var operation = current.operation() || "unknown";
var isPreviousNull = previous === null;
var createdOn = current.getValue("sys_created_on");
var updatedOn = current.getValue("sys_updated_on");
var isNewRecord = createdOn === updatedOn;
var action = "update";
if (isPreviousNull && isNewRecord) {
action = "insert";
}
var body = {
action_type: action,
number: current.getValue("number"),
sys_id: current.getUniqueValue(),
short_description: current.getValue("short_description"),
description: current.getValue("description"),
state: current.getDisplayValue("state"),
impact: current.getDisplayValue("impact"),
urgency: current.getDisplayValue("urgency"),
comments: getLastComment(current.getUniqueValue()),
{original.key}: current.getDisplayValue("{original.key}")
};
try {
var endpoint = "";
var request = new sn_ws.RESTMessageV2();
request.setHttpMethod("POST");
request.setEndpoint(endpoint);
request.setRequestHeader("Content-Type", "application/json");
request.setRequestBody(JSON.stringify(body));
request.executeAsync();
} catch (ex) {
gs.error("Error sending webhook: " + ex.message);
}
})(current, previous);
```
7. 提交保存。
## 同步信息
### 表单字段
| ServiceNow | Flashduty | 备注 |
| ------------------- | ------------- | ----- |
| Short\_description | Title | 标题 |
| Description | Description | 描述信息 |
| Additional comments | Comments | 评论 |
| State | Progress | 状态 |
| Urgency | Severity | 严重程度 |
| Others | Custom Fields | 自定义字段 |
### 状态映射
| ServiceNow | Flashduty | 备注 |
| ----------- | ---------- | --------- |
| New | Triggered | 触发 |
| In Progress | Processing | 待处理 |
| On Hold | Snoozed | 默认暂缓 2 小时 |
| Resolved | Closed | 关闭 |
| Closed | Closed | 关闭 |
| Canceled | Closed | 关闭 |
### 优先级映射
只有 ServiceNow 的 Urgency 值变化时,才会影响 Flashduty 的 Severity
| ServiceNow | Flashduty | 备注 |
| ---------- | --------- | -- |
| Low | Info | 提示 |
| Medium | Warning | 警告 |
| High | Critical | 灾难 |
## 常见问题
新建 ServiceNow 用户时,UserID 是否可以自定义?
可以自定义,文档指引中使用 flashduty 作为 UserID,是为了更好的标识该用户用于 Incident 同步
配置集成时提示 401 错误
提示 401 一般是密码错误导致的,请检查密码是否正确,或者重新设置新的密码(在配置密码时,请勿勾选 Password needs reset 选项)
# 结合外部数据实现动态分派
Source: https://docs.flashduty.com/zh/on-call/practices/dynamic-dispatch-with-external-data
通过标签映射与动态分派,让告警自动路由到正确的处理人,无需频繁修改分派策略
## 为什么需要动态分派
在企业运维中,监控对象(主机、服务、数据库等)成千上万,且负责人随组织架构调整频繁变化。如果为每个对象单独维护分派策略,成本极高且容易出错。
**动态分派** 解决的正是这个问题:您只需配置一条分派策略作为"模板",系统会根据告警携带的特定标签,自动替换或追加该策略中的通知对象。这样,无论负责人如何变更,您只需更新标签数据,无需修改分派策略本身。
## 工作原理
动态分派的核心流程分为三步:
告警通过集成接入后,进入协作空间,匹配到已配置的分派策略。
系统检测到告警携带了特定标签(如 `layer_person_reset_0_emails=bob@corp.com` 或 `layer_person_append_0_emails=bob@corp.com`),自动替换或追加分派策略中环节 1 的通知对象。
按照调整后的分派策略进行通知。分派完成后,系统自动移除这些控制类标签,保持告警详情页整洁。
动态分派并不是独立工作的,它依赖于协作空间中已有的分派策略。您需要预先配置一条分派策略作为"模板"——动态标签只会替换或追加其中的通知对象(人员、团队或群聊机器人),策略中的其他配置(如通知方式、超时时间、升级规则等)保持不变。
详细的标签参数说明请参考 [动态分派](/zh/on-call/advanced/dynamic-notifications)。
## 如何生成动态标签
动态分派的关键在于告警需要携带正确的标签。以下两种方式都可以实现,您可以根据实际情况选择。
本文以 `reset` 替换模式为例。如果您希望保留模板分派策略中的原有对象,并额外加入负责人、团队或群聊机器人,可使用 `append` 追加模式。完整参数请参考 [动态分派](/zh/on-call/advanced/dynamic-notifications)。
### 方式一:在监控系统中直接打标
如果您拥有监控系统的配置权限,且监控系统支持自定义标签(如 Prometheus、Nightingale、Zabbix),直接在告警规则中添加标签即可:
* **标签键**:`layer_person_reset_0_emails`
* **标签值**:`bob@corp.com`
此方式配置最简单,适合负责人相对固定的场景。但人员变更时需要同步修改监控系统的告警规则。
### 方式二:通过标签映射自动生成
如果您无法修改监控配置,或者希望将"监控对象 → 负责人"的对应关系集中管理(例如从 CMDB、配置平台或任何外部数据源同步),推荐使用 **标签映射** 功能。
此方式通过建立一张映射表,将告警中已有的基础标签(如 `host`)自动"翻译"为动态分派标签,无需修改监控系统。
梳理监控对象与负责人的对应关系。小规模数据可以在页面中手动输入;大规模数据建议整理为 CSV 文件。
CSV 中的目标列名必须使用动态分派的专用参数名(如 `layer_person_reset_0_emails`)。
| host(源标签) | layer\_person\_reset\_0\_emails(目标标签) |
| :------------ | :-------------------------------------- |
| web-server-01 | [bob@corp.com](mailto:bob@corp.com) |
| db-server-02 | [alice@corp.com](mailto:alice@corp.com) |
数据来源不限——CMDB、配置管理平台、运维系统或 Excel 表格均可,满足上述格式即可。
将数据录入系统,建立一个可复用的映射"字典"。
1. 进入 **集成中心 → 标签映射**。
2. 点击 **创建标签映射**。
3. 录入数据:
* **上传文件**:上传 CSV 文件,适合批量操作。
* **手动输入**:在页面上逐条添加,适合少量数据维护。
4. 保存后,您将获得一个可供集成引用的映射表。
如需与外部系统保持实时同步,推荐使用 [Flashduty API](https://developer.flashcat.cloud/flashduty/enrichment/mapping-data-upsert) 自动更新映射表,实现全自动的配置同步。
在告警集成中引用映射表,让系统在告警接入时自动补全动态标签。
1. 进入 **集成中心 → 标签增强**。
2. 找到目标告警集成(如 Zabbix 集成),进入详情。
3. 选择 **标签增强** 页签,动作类型选择 **标签映射**。
4. **选择映射表**:选择上一步创建的映射表。
5. **配置映射关系**:
* **源标签**:选择 `host`。
* **目标标签**:选择 `layer_person_reset_0_emails`。
完成后,系统会在告警接入时自动根据 `host` 的值查表,生成对应的动态分派标签。
在目标协作空间中配置一条分派策略。此策略中的通知对象可以设为任意值(例如一个默认团队),它仅作为"模板"——实际分派时,通知对象会被动态标签替换或追加。
策略中的其他配置项(通知方式、超时升级等)会正常生效。
详细配置方法请参考 [分派策略](/zh/on-call/channel/escalation-rule)。
## 验证效果
完成配置后,触发一条测试告警来验证:
1. **查看分派过程**:在 **故障详情 → 时间线** 中,您会看到类似日志:"基于动态标签,分派对象已重置为 [bob@corp.com](mailto:bob@corp.com)"。
2. **检查告警标签**:在告警详情页,您**不会**看到 `layer_person_reset_xxx` 标签——这些控制指令在生效后会被系统自动清理。
## 延伸阅读
查看完整的动态标签参数说明和推送示例
了解如何根据已有标签自动生成新标签
# 企微机器人 @ 提醒处理人
Source: https://docs.flashduty.com/zh/on-call/practices/wecom-bot-mention
配置企微群聊机器人在推送告警通知时 @ 提醒对应的处理人员,确保关键告警不被遗漏
## 为什么需要 @ 提醒
企微群聊中消息量大,处理人员容易忽略告警通知。通过开启 **@ 提醒**,机器人推送故障通知时会自动 @ 对应的处理人员,确保相关负责人第一时间收到提醒。
Flashduty 支持两种方式实现企微机器人的 @ 提醒,二者的区别如下:
| 对比项 | 默认方式(手机号匹配) | 映射表方式(user\_id 匹配) |
| :--------- | :-------------------------- | :---------------------------- |
| **匹配原理** | 通过 Flashduty 成员绑定的手机号查找企微成员 | 通过映射表中的邮箱与企微 user\_id 对应关系查找 |
| **@ 提醒位置** | 通知消息底部单独展示 | 通知消息内容中内联展示 |
| **维护成本** | 无需额外维护,只要手机号一致即可 | 需要维护邮箱与企微 user\_id 的映射表 |
| **适用场景** | 手机号在 Flashduty 和企微中保持一致 | 手机号不一致,或希望 @ 提醒与通知内容在同一条消息中展示 |
## 方式一:默认方式(手机号匹配)
这是最简单的方式,无需额外配置。系统通过成员在 Flashduty 中绑定的手机号,自动匹配企微中对应的成员。
### 前提条件
* 成员在 Flashduty 中绑定的手机号与企微账号的手机号 **完全一致**
### 配置步骤
确保 Flashduty 成员的手机号与企微账号的手机号相同。您可以在 **平台管理 → 成员管理** 中查看和修改成员手机号。
进入目标协作空间的 **分派策略**,找到企微机器人通知渠道,展开 **高级配置**,开启 **@ 提醒** 开关。
此方式下,如果成员的手机号在两个平台中不一致,@ 提醒将不会生效。请优先确认手机号的一致性。
## 方式二:映射表方式(user\_id 匹配)
如果成员手机号在两个平台中不一致,或者您希望 @ 提醒与通知内容在同一条消息中内联展示,可以使用映射表方式。
此方式需要您维护一张 Flashduty 成员邮箱与企微 user\_id 的对应关系表。
### 前提条件
* 已获取企微成员的 user\_id(可通过企业微信管理后台或 API 获取)
### 配置步骤
登录 [企业微信管理后台](https://work.weixin.qq.com/wework_admin/frame#contacts),进入 **通讯录**,点击目标成员查看详情,找到 **账号** 字段,即为该成员的 user\_id。
您也可以通过企业微信 API 批量获取。
1. 进入 Flashduty **平台管理 → 映射表管理**。
2. 点击 **创建映射表**,类型选择 **企微**。
3. 录入 Flashduty 成员邮箱与对应的企微 user\_id:
| email | wecom\_userid |
| :-------------------------------------- | :------------ |
| [bob@corp.com](mailto:bob@corp.com) | bob\_wecom |
| [alice@corp.com](mailto:alice@corp.com) | alice\_wecom |
进入目标协作空间的 **分派策略**,找到企微机器人通知渠道:
1. 展开 **高级配置**,开启 **@ 提醒** 开关。
2. 在 **用户信息映射表** 下拉框中,选择上一步创建的映射表。
映射表需要您自行维护。当团队成员发生变动时,请及时更新映射表中的对应关系,否则新成员将无法被 @ 到。
## 验证效果
完成配置后,触发一条测试告警来验证 @ 提醒是否生效:
1. 确认目标协作空间已配置企微机器人作为群聊通知渠道。
2. 触发测试告警,观察企微群聊中的通知消息。
3. 确认处理人员被正确 @ 到。
如果 @ 提醒未生效,请参考以下排查清单:
* 确认已开启 **@ 提醒** 开关
* 确认成员在 Flashduty 中绑定的手机号与企微账号手机号 **完全一致**(包括国际区号)
* 确认该成员在企微机器人所在的群聊中
* 确认已开启 **@ 提醒** 开关,且已选择正确的 **用户信息映射表**
* 确认映射表中 Flashduty 成员邮箱和企微 user\_id 的对应关系正确
* 确认企微 user\_id 填写无误(可在企微管理后台通讯录中核实)
* 确认该成员在企微机器人所在的群聊中
## 延伸阅读
了解所有机器人类型的配置方法和高级选项
了解分派策略的通知方式和群聊配置
# 微信小程序
Source: https://docs.flashduty.com/zh/rum/analytics/miniprogram
深入了解 Flashduty 微信小程序 RUM 分析看板的核心功能,掌握小程序性能监控、setData 调优和启动耗时分析的关键指标
Flashduty 微信小程序 RUM 分析看板提供开箱即用的可视化仪表板,自动采集并分析小程序的用户会话、启动耗时、页面渲染、setData 调用等多维度数据,帮助您全面洞察小程序真实运行状况,快速定位性能瓶颈与异常问题,持续优化用户体验。
分析看板包含 2 个核心分析维度:**概览**、**性能分析**
## 概览 — 关键指标一目了然
概览模块聚焦于小程序多维度的核心指标,帮助您快速把握整体健康状况。
#### 流量与会话
* **UV**:去重后的独立访客数。结合趋势图可洞察用户活跃规律。
* **会话数**:小程序被打开使用的会话总数,点击卡片可下钻查看具体会话列表。
* **用户访问趋势**:以时序图同时展示 UV 与 Session 的变化趋势,识别访问高峰与异常波动。
#### 核心指标
* **错误数(error\_count)**:监控小程序错误事件的总数与时序趋势,及时发现异常峰值。
* **会话错误率(session error rate)**:发生错误的会话占总会话的比例,反映小程序整体稳定性。
* **应用启动时长 P75(appLaunchTime P75)**:监控小程序冷启动 + 热启动整体耗时的 P75 分位值,评估启动性能表现。启动时长直接影响用户的第一印象。
* **首次渲染 P75(firstRender P75)**:监控页面从开始加载到首次渲染完成耗时的 P75 分位值,反映页面"白屏"时间。
* **setData 调用次数(setDataCount 平均值)**:监控页面平均每次访问的 `setData` 调用次数。过高的调用频次会增加 JS 与渲染线程的通信开销。
* **setData 耗时 P75(setDataDuration P75)**:监控单次 `setData` 调用耗时的 P75 分位值。
#### 会话分析
* **平均会话时长**:会话总时长除以会话总数,评估用户粘性与使用深度。结合时序图可识别活跃用户行为变化。
## 性能分析 — 全面掌控小程序体验
性能分析模块专注于小程序启动、页面渲染、`setData` 等核心体验指标的全链路监控。
#### 核心性能指标
顶部展示 5 个关键性能指标卡片,点击任一卡片可切换下方趋势图与样本分布的统计维度:
| 指标 | 采集字段 | 说明 |
| --------------------- | ------------------ | -------------------------- |
| **应用启动时长 P75** | `app_launch` | 小程序启动耗时的 P75 分位值 |
| **首次渲染 P75** | `first_render` | 页面首次渲染完成耗时的 P75 分位值 |
| **页面加载时长 P75** | `loading_time` | 页面从打开到完全加载完成耗时的 P75 分位值 |
| **setData 调用次数(平均值)** | `setdata_count` | 单次页面访问内 `setData` 调用次数的平均值 |
| **setData 耗时 P75** | `setdata_duration` | 单次 `setData` 调用耗时的 P75 分位值 |
每个卡片左上角显示健康状态徽标(良好 / 中等 / 差),基于内置阈值评估当前指标。
#### 趋势分析
下方的趋势图支持选择 **趋势模式**,按不同维度展开当前指标:
| 趋势模式 | 说明 |
| --------- | ------------------------------------ |
| **整体** | 不分维度,展示当前指标的整体时序趋势 |
| **按版本** | 按应用版本号(version)分组,对比新旧版本性能差异 |
| **按环境** | 按环境变量(env)分组,对比不同环境的性能表现 |
| **按加载类型** | 按 `view_loading_type` 分组,对比冷启动与热启动性能 |
| **按操作系统** | 按 `os_name` 分组,识别系统级兼容性差异 |
切换 **按版本** 时可对比新版本灰度阶段的性能数据,验证发版质量;切换 **按加载类型** 时可单独观察冷启动(`initial_load`)和热启动(`route_change`)的耗时差异。
#### 样本分布
样本分布柱状图按时间区间统计当前指标的样本数量分布,识别长尾问题。例如观察应用启动时长时,分布图能清晰展示有多少用户的启动耗时落在 1s 以内、1-2s、2s 以上等区间。
#### 页面性能明细
按页面(视图名称)统计各项性能指标,识别加载缓慢或 `setData` 过于频繁的页面:
| 列 | 说明 |
| ---------------- | ----------------------------------- |
| 视图名称 | 小程序页面路由路径 |
| 访问次数 | 该页面的 view 事件总数,附直方图条形展示相对热度 |
| 应用启动时长 | 落在该页面会话内的启动耗时 P75 |
| 首次渲染 | 该页面首次渲染耗时 P75 |
| 页面加载时长 | 该页面完全加载耗时 P75 |
| setData 调用次数 | 该页面平均 setData 调用次数 |
| setData 耗时 | 该页面单次 setData 耗时 P75 |
| onLoad → onShow | 该页面从 `onLoad` 到 `onShow` 之间的耗时 P75 |
| onShow → onReady | 该页面从 `onShow` 到 `onReady` 之间的耗时 P75 |
点击表格中的任一行可跳转到该页面的详细分析视图。
#### 启动类型趋势
底部两张图分别展示冷启动(`initial_load`)与热启动(`route_change`)的对比情况:
* **启动类型趋势**:冷启动与热启动次数随时间的变化趋势,识别业务流量结构变化。
* **启动耗时趋势**:冷启动与热启动耗时的时序对比,冷启动通常显著长于热启动;如果两者差距异常缩小或拉大,往往意味着启动逻辑发生了变化。
**冷启动 vs 热启动**
* **冷启动(initial\_load)**:用户首次进入小程序或小程序被微信回收后重新打开,需要完整初始化运行时和加载首页。
* **热启动(route\_change)**:小程序在后台短时间被唤回,无需重新初始化,耗时显著更短。
## 常见问题
* **应用启动时长(app\_launch)**:从用户点击小程序图标或入口到 `App.onLaunch` 执行完成的总耗时,包含运行时初始化、首页代码包加载、`App.onLaunch` 执行等阶段。
* **首次渲染(first\_render)**:从页面开始加载到该页面首次完成渲染的耗时,反映页面"白屏"时间。
* 一次冷启动通常 = 应用启动时长 + 首页首次渲染时间,二者从不同角度衡量启动体验。
`setData` 是小程序逻辑层向渲染层通信的核心 API,每次调用都会触发跨线程通信和差量计算。常见问题:
* **频繁调用**:在循环或事件中高频调用 `setData`,导致渲染线程持续繁忙
* **数据体积过大**:一次 `setData` 传递的数据过大,跨线程序列化耗时显著
* **更新无关数据**:把整个 `data` 传给 `setData`,而不是仅传递变化的字段
**优化建议:**
* 合并多次 `setData` 调用,使用局部对象传参
* 使用路径表达式更新嵌套字段,如 `this.setData({ 'list[0].name': value })`
* 避免在频繁触发的事件(scroll、input)中直接调用 `setData`,使用节流/防抖
* 关注页面明细表中 `setData 调用次数` 和 `setData 耗时` 列异常高的页面,优先优化
分位数(Percentile)是统计学中衡量数据分布的重要指标:
| 分位数 | 含义 |
| ------------ | --------------------------- |
| **P50(中位数)** | 50% 的用户体验优于此值,50% 的用户体验劣于此值 |
| **P75** | 75% 的用户体验优于此值,25% 的用户体验劣于此值 |
| **P90** | 90% 的用户体验优于此值,10% 的用户体验劣于此值 |
**为什么使用 P75 而不是平均值?**
* 平均值容易被极端值影响,可能不能代表大多数用户的真实体验
* P75 更能反映大部分用户的体验情况,是业界常用的性能评估标准
关注 **应用启动时长 P75** 指标,并通过样本分布柱状图识别长尾。切换趋势模式为 **按加载类型** 单独观察冷启动表现。
减少首包体积,使用分包加载(subpackages)和分包预下载,避免一次性加载所有页面代码。
把第三方 SDK 初始化、埋点上报、远程配置拉取等非关键任务延迟到首屏渲染之后执行。
* 减少首屏依赖的网络请求数量,合并接口
* 使用本地缓存或骨架屏,避免长时间白屏
* 控制首屏 `setData` 的数据体积
切换趋势模式为 **按版本**,对比新旧版本启动耗时,及时发现回退。
这些是小程序页面生命周期内部各阶段的耗时,可用于精确定位渲染慢的环节:
* **onLoad → onShow**:页面收到 `onLoad` 到 `onShow` 之间的耗时,主要反映 `onLoad` 中同步逻辑(参数解析、首屏数据预处理等)的耗时。
* **onShow → onReady**:页面 `onShow` 到 `onReady` 之间的耗时,反映首次渲染完成所需的时间,包含模板编译和首批 `setData` 的渲染。
如果首次渲染时间偏长,可结合这两个分段指标判断是 `onLoad` 中的逻辑阻塞,还是首次渲染本身耗时过长。
Flashduty RUM 通常在数据产生后的 **1-3 分钟**内完成采集和展示。在网络状况良好的情况下,大部分数据可实现准实时更新。
## 延伸阅读
了解如何在微信小程序中接入 RUM SDK,完成应用初始化
了解 SDK 自动采集的事件类型与 view 字段口径
深入配置代理、分布式追踪、采样率与手动上报
查看 SDK 支持的小程序基础库版本与平台 API 要求
# Native
Source: https://docs.flashduty.com/zh/rum/analytics/native
深入了解 Flashduty Native(Android/iOS)RUM 分析看板的核心功能,掌握移动应用性能监控、异常追踪和资源分析的关键指标
Flashduty Native RUM 分析看板提供开箱即用的可视化仪表板,自动采集并分析用户会话、应用性能、崩溃异常、网络请求等多维度数据,帮助您全面洞察移动应用真实运行状况,快速定位性能瓶颈与异常问题,持续优化用户体验。
分析看板包含 4 个核心分析维度:**概览**、**性能分析**、**异常分析**、**资源分析**
**平台差异**
Native 看板适用于 Android、iOS、HarmonyOS 和 Flutter 应用,不同平台存在以下差异:
* **Flutter**:一个 Flutter 应用同时覆盖 Android 和 iOS 两端,筛选栏会额外常驻 `os_name` 筛选项,便于按设备系统切片分析;概览与异常分析中,**ANR 率**(来自 Android 设备)与 **App Hang 率**(来自 iOS 设备)两张卡片并列展示。
* **HarmonyOS**:SDK 暂未上报性能与卡顿指标,因此不展示卡顿相关卡片,也不提供「性能」页签。
* **Electron**:不使用 Native 看板——Electron 应用复用 **Web 分析看板**,但 UV 改用匿名 ID 口径(Electron SDK 不上报 `usr_id`),详见下方「指标口径参考」。
## 概览 — 关键指标一目了然
概览模块聚焦于移动应用多维度的核心指标:
* **流量指标** - 监控 UV(独立访客数)、会话数,帮助您把握整体用户活跃趋势
* **核心健康指标** - 突出显示三个移动应用核心指标:崩溃次数、无崩溃率、应用卡顿率,快速识别应用稳定性问题
* **用户访问趋势** - 通过时序图追踪 UV 和 Session 的变化趋势,洞察用户活跃规律
* **用户分布** - 结合地理位置分析用户来源,了解区域用户活跃情况
* **会话分析** - 统计会话平均时长分布趋势,评估用户粘性与使用深度
* **版本分布** - 监控不同系统版本(Android/iOS)和应用版本的用户占比,为兼容性优化与版本迭代提供数据支撑
## 性能分析 — 全面掌控应用体验
性能分析模块专注于应用启动、页面渲染、交互流畅度等核心体验指标的全链路监控。
#### 核心性能指标
顶部展示四个关键性能指标的 P75 分位值:
* **应用启动时间(P75)**:监控应用启动耗时的 P75 分位数,评估启动性能表现。启动时间直接影响用户的第一印象和使用意愿。
* **帧率(P75)**:展示应用运行时帧率的 P75 分位数,衡量画面流畅度。目标为 60fps,数值越高表示交互越流畅。
* **CPU 消耗(P75)**:追踪 CPU 占用率的 P75 分位数,识别计算密集型操作。过高的 CPU 消耗会导致设备发热和耗电增加。
* **内存使用(P75)**:监控应用内存占用的 P75 分位数,及时发现内存泄漏或异常增长。
#### APP 启动时间分析
* **启动时间趋势图**:展示应用启动时间随时间的变化趋势,帮助您评估启动优化效果,及时发现性能退化。
* **样本分布柱状图**:按时间区间统计启动耗时的分布情况(如 0.9425s-0.9642s、1.1162s-1.1379s 等),了解用户真实启动体验的分布特征,识别性能长尾问题。
#### 视图性能明细
按视图名称(页面/Activity/ViewController)统计各项性能指标:
* **访问次数**:展示各视图的访问量,识别核心高频页面。
* **启动时间**:监控各视图的加载耗时,定位加载缓慢的页面。
* **帧率**:追踪各视图运行时的帧率表现,识别渲染性能问题。
* **CPU 消耗**:统计各视图的 CPU 占用情况,优化计算密集型页面。
* **内存使用**:监控各视图的内存占用,发现内存泄漏风险。
#### 流畅度分析
按视图名称统计应用流畅度相关指标:
* **慢帧数**:统计渲染耗时超过阈值的帧数(通常为 16.67ms,即低于 60fps),识别卡顿问题。慢帧会导致用户感知到明显的界面不流畅。
* **冻结帧数**:记录界面完全冻结的帧数(通常超过 700ms),这些是严重影响用户体验的性能问题。
* **长任务数**:追踪主线程长时间运行的任务数量(通常阈值为 100ms 或更长),定位性能瓶颈。长任务会阻塞用户交互和界面更新。
* **卡顿频率**:统计应用卡顿的发生频率(次/秒),评估整体流畅度表现。
#### 内存分析
按视图名称统计内存使用详情:
* **平均内存**:展示各视图的平均内存占用,了解常规内存消耗水平。
* **峰值内存**:记录各视图运行期间的内存使用峰值,识别内存压力高峰,预防因内存不足导致的系统终止(OOM)。
* **P75 内存**:显示内存占用的 P75 分位数,反映大部分用户的内存使用情况,比平均值更能代表真实体验。
## 异常分析 — 快速定位与诊断错误
异常分析模块为您提供全方位的错误监控与诊断能力。
#### 核心稳定性指标
* **崩溃次数**:监控应用崩溃的发生总数和趋势,及时发现异常峰值。崩溃会导致应用强制退出,严重影响用户体验。
* **无崩溃率**:跟踪无崩溃会话占比,评估应用整体稳定性表现。行业标准建议无崩溃率应保持在 99.5% 以上。
* **ANR 率**:统计 Android 应用无响应(Application Not Responding)的发生比例。ANR 表示应用主线程被阻塞超过 5 秒,用户会看到"应用无响应"对话框。
* **应用卡顿率**:监控发生卡顿的会话占总会话的比例,用于评估应用流畅度问题的影响范围。卡顿通常指主线程长时间阻塞导致的界面冻结、响应延迟或帧率下降,影响用户交互体验。
#### 错误数据统计
* **错误数**:展示错误总数和时序趋势,了解应用健康状况的整体变化。
* **错误类型分布趋势图**:通过堆叠面积图展示崩溃错误(crash\_count)与非崩溃错误(non\_crash\_count)随时间的分布变化,快速识别异常时段和错误类型变化趋势。
* **崩溃错误(crash\_count)**:导致应用强制退出的严重错误
* **非崩溃错误(non\_crash\_count)**:被捕获的异常,应用可继续运行但功能可能受影响
#### 页面 Crash 排行(Top10)
列出崩溃次数最多的页面或视图控制器,每条记录包含:
* **错误类型**:崩溃的异常类型(如 java.lang.RuntimeException、SIGTRAP 等)
* **错误信息**:错误的详细描述,帮助快速定位问题
* **错误数**:该错误在该页面发生的总次数
* **会话数**:受该错误影响的会话(用户访问)数量
此排行帮助您优先处理影响最大的页面崩溃问题。
#### 热门 Issue(Top10)
展示影响用户最多的问题排行,每个 Issue 是经过聚合的错误集合,包含:
* **错误类型**:Issue 的主要错误类型(如 java.lang.RuntimeException、TypeError、ReferenceError 等)
* **错误信息**:Issue 的典型错误描述,点击可查看详细堆栈和会话信息
* **错误数**:该 Issue 包含的错误总次数
* **会话数**:受该 Issue 影响的会话数量
**注意**:一个 Issue 可能聚合了多次相同根因的错误。关于 Issue 聚合策略,可查看[异常聚合](https://docs.flashduty.com/zh/flashduty/rum/error-grouping)。
#### 错误类型分布
* **错误类型占比(饼图)**:展示不同错误类型的占比(如 ReferenceError、java.lang.RuntimeException 等),快速识别主要错误来源。
* **错误类型分布趋势(堆叠面积图)**:监控各错误类型随时间的变化趋势,及时发现新增错误类型或某类错误的异常增长。
#### 版本 Crash 分布
* **版本 Crash 分布(饼图)**:统计不同应用版本的崩溃分布情况,识别高风险版本。
* **版本 Crash 分布趋势(堆叠面积图)**:监控各版本崩溃随时间的变化,评估新版本质量,必要时进行热修复或回滚。
#### 系统版本异常分布
* **系统版本异常分布(饼图)**:统计不同操作系统版本(如 Android 11、Android 12、iOS 15 等)的异常分布情况,识别系统兼容性问题。
* **系统版本异常趋势(堆叠面积图)**:监控各系统版本异常随时间的变化,为系统兼容性优化提供数据支撑。
如需深入分析具体错误,可参阅[错误跟踪](https://docs.flashduty.com/zh/flashduty/rum/error-tracking)了解如何调查关键错误、查看错误堆栈、追踪新错误的出现,以及如何在问题修复后验证效果。
## 资源分析 — 精细化网络性能优化
资源分析模块帮助您深入了解应用的网络请求性能,识别优化机会:
* **请求数**:监控网络请求总量的变化趋势,了解应用网络活跃度。
* **请求成功率**:跟踪请求成功的比例,及时发现网络异常。
* **中位数请求时间**:展示请求耗时的中位数变化(如 p50、p75、p95),评估整体网络性能水平。
* **慢请求**:统计响应时间超过阈值的慢请求趋势,定位性能瓶颈。
* **异常请求**:监控失败或错误请求的发生情况,快速识别接口问题。
* **资源请求状态分布**:
* **请求状态码占比**:通过饼图展示不同 HTTP 状态码的分布(如 200、404、500),识别异常请求类型。
* **请求状态码趋势**:监控各状态码随时间的变化,及时发现异常峰值。
* **请求方式分布**:
* **请求方法占比**:展示不同 HTTP 方法(GET、POST 等)的使用分布。
* **请求方法趋势**:分析各请求方法的时序变化。
* **静态资源**:
* **静态资源调用排行**:列出调用频率最高的静态资源(如图片、字体、配置文件等),了解资源使用热度。
* **静态资源响应排行**:识别响应最慢的静态资源,优化资源加载性能。
* **网络调用排行**:
* **Host 排行**:按请求来源(Host)统计请求数,识别主要依赖的服务端点。
* **资源耗时排行**:列出耗时最长的网络请求,包含耗时详情(DNS 解析、TCP 连接、SSL 握手、首字节时间、响应时间等),精准定位性能瓶颈。
## 常见问题
状态码为 0 通常由以下原因导致:
* **请求被取消** - 用户在请求完成前离开页面或取消操作,导致请求中断
* **网络中断或超时** - 请求在发送过程中遇到网络中断、超时等异常情况,可能导致状态码无法正常返回
* **证书验证失败** - HTTPS 请求的 SSL 证书验证失败,连接建立前就被中断
* **SDK 兼容性** - 在极少数情况下,特定系统版本或设备可能存在兼容性问题,导致数据采集不完整
* **错误数** - 指原始错误事件的总数,包括每一次错误发生的记录
* **Issue 数量** - 指经过聚合后的问题数量。Flashduty 会根据错误堆栈、错误类型、发生位置等信息,将相似的错误聚合为同一个 Issue
**示例:**
```
错误总数:100 次
Issue 数量:5 个
```
这表示 100 次错误被聚合成了 5 个不同的 Issue,每个 Issue 可能由不同的根因导致。
聚合的优势:
* 便于定位问题根因:相同根因的错误归为一个 Issue,避免重复处理
* 优先级排序:通过影响范围(错误数、会话数)识别最需要修复的问题
* 追踪修复效果:修复一个 Issue 后,可观察该 Issue 下所有错误是否消失
详细了解 [异常聚合策略](https://docs.flashduty.com/zh/flashduty/rum/error-grouping)。
通过"页面 Crash 排行"和"热门 Issue"快速定位影响最大的崩溃问题。
点击具体 Issue 查看详细的错误堆栈和用户环境信息,精准定位问题代码。
通过"系统版本 Crash 分布"识别特定系统版本的兼容性问题。
通过"版本 Crash 分布"评估新版本质量,必要时进行热修复或回滚。
合理使用 try-catch、全局异常处理器,避免未捕获异常导致崩溃。
分位数(Percentile)是统计学中衡量数据分布的重要指标:
| 分位数 | 含义 |
| ------------ | --------------------------- |
| **P50(中位数)** | 50% 的用户体验优于此值,50% 的用户体验劣于此值 |
| **P75** | 75% 的用户体验优于此值,25% 的用户体验劣于此值 |
| **P90** | 90% 的用户体验优于此值,10% 的用户体验劣于此值 |
| **P95** | 95% 的用户体验优于此值,5% 的用户体验劣于此值 |
**为什么使用 P75 而不是平均值?**
* 平均值容易被极端值影响,可能不能代表大多数用户的真实体验
* P75 更能反映大部分用户的体验情况,是业界常用的性能评估标准
* Google 推荐使用 P75 作为核心性能指标
**示例:**
```
应用启动时间 P75 = 1.7s
→ 表示 75% 的用户启动时间在 1.7s 以内,25% 的用户超过 1.7s
内存使用 P75 = 233MB
→ 表示 75% 的场景下内存占用在 233MB 以内
```
这些都是衡量应用流畅度的重要指标:
| 指标类型 | 阈值 | 用户体验影响 | 优先级 |
| --------------------- | ------------------------ | ------------- | ---------------- |
| **慢帧(Slow Frame)** | 渲染耗时 > 16.67ms(60fps 标准) | 轻微卡顿 | 偶尔出现可接受,频繁出现需要优化 |
| **冻结帧(Frozen Frame)** | 渲染耗时 > 700ms | 界面完全冻结,用户无法交互 | 严重影响体验,必须修复 |
| **长任务(Long Task)** | 主线程执行 > 100ms | 阻塞用户交互和界面更新 | 需要优化 |
**长任务常见原因:**
* 复杂计算
* 大数据处理
* 同步 I/O 操作
**优化建议:**
* 将耗时操作移至后台线程
* 分批处理大量数据
* 优化算法复杂度
* 避免在主线程进行同步网络请求或磁盘 I/O
通过"页面加载耗时排行"识别加载最慢的页面,优先优化。
* 采用分页加载或虚拟列表技术,避免一次性加载大量数据
* 使用数据预加载和缓存策略,减少等待时间
* 优化网络请求,合并接口调用
* 减少视图层级嵌套,降低布局计算复杂度
* 避免过度使用透明视图和圆角效果
* 延迟加载非首屏内容
* 使用合适的图片格式和尺寸
* 采用渐进式加载或占位图
* 对图片进行压缩和缓存
将复杂视图的渲染操作放到后台线程执行。
**ANR(Application Not Responding)** 是 Android 系统的应用无响应机制:
* 当应用主线程被阻塞超过 5 秒时,系统会弹出"应用无响应"对话框
* 用户可以选择"等待"或"关闭应用"
* ANR 严重影响用户体验,可能导致用户卸载应用
ANR 常见原因:
* **主线程执行耗时操作**:同步网络请求、大文件读写、复杂计算、数据库操作
* **主线程等待锁**:多线程死锁、等待其他线程释放锁
* **系统资源不足**:CPU 被其他应用占用、内存不足导致频繁 GC
**降低 ANR 率的方法:**
1. **避免主线程阻塞** - 将耗时操作移至后台线程(使用 AsyncTask、Coroutines、RxJava 等)
2. **优化锁使用** - 减少锁的持有时间,避免嵌套锁,使用无锁数据结构
3. **优化生命周期方法** - onCreate/onResume 等方法要快速返回
4. **监控和分析** - 使用 StrictMode 发现主线程违规,通过 RUM 看板定位问题
通过"长任务监控"和"卡顿时长分布"识别导致卡顿的具体代码。
将耗时操作(如网络请求、数据库读写、复杂计算、大文件 I/O)移至后台线程。
* 减少视图层级,降低布局复杂度
* 避免在主线程进行复杂的视图计算
* 使用 RecyclerView(Android)或 UITableView/UICollectionView(iOS)的优化技巧
* 合理使用硬件加速
* 实现视图复用机制
* 优化 item 布局复杂度
* 避免在 item 绑定时执行耗时操作
结合性能分析看板和系统工具(Android Profiler、Xcode Instruments)定位具体卡顿代码。
建议根据业务特点和用户预期,设置合理的卡顿检测阈值(建议 200-500ms)。
**登录态用户识别**
对于需要用户登录的应用(如电商、社交、金融等),您可以在用户登录后调用 SDK 的用户标识方法:
* Android: 参考 [Android 用户会话配置](/zh/rum/sdk/android/advanced-config#追踪用户会话)
* iOS: 参考 [iOS 用户会话配置](/zh/rum/sdk/ios/advanced-config#追踪用户会话)
**设备指纹识别**
对于无登录态的应用,推荐基于设备信息生成稳定的设备指纹并上报用户标识:
| 平台 | 可用标识符 |
| ----------- | --------------------------------------- |
| **Android** | Android ID、IMEI(需权限)、广告 ID |
| **iOS** | IDFV(Identifier for Vendor)、IDFA(需用户授权) |
通过"资源耗时排行"定位响应时间最长的接口。
查看 DNS 解析、TCP 连接、SSL 握手、首字节时间等各阶段耗时,精准定位瓶颈。
| 优化方向 | 具体措施 |
| ---------- | ------------------------ |
| **DNS 优化** | 使用 DNS 缓存、HTTPDNS |
| **连接优化** | 启用 HTTP/2、连接复用、减少重定向 |
| **传输优化** | 启用 GZIP 压缩、优化数据格式、减少请求体积 |
| **接口优化** | 优化后端接口性能、使用 CDN 加速静态资源 |
* 查看"应用启动时间(P75)"指标,了解大部分用户的启动体验
* 通过"启动时间趋势图"评估优化效果,避免性能退化
* 查看"样本分布柱状图"识别长尾问题
将非必要的初始化操作延迟到首屏渲染后执行,缩短启动时间。
减少启动期间加载的第三方 SDK 和库,采用懒加载策略。
降低首页视图层级复杂度,减少首次渲染耗时。
* **Android**: 使用 App Startup Library 管理组件初始化顺序
* **iOS**: 利用 Lazy Initialization 延迟初始化非关键组件
Flashduty RUM 通常在数据产生后的 **1-3 分钟**内完成采集和展示。在网络状况良好的情况下,大部分数据可实现准实时更新。
## 指标口径参考
### 概览指标
| 指标 | 采集字段 | 说明 |
| ------ | ---------------------------- | ----------------- |
| UV | usr\_anonymous\_id / usr\_id | 去重后的用户总数,详见下方口径说明 |
| 会话数 | session\_id | 应用被打开使用的总会话数量 |
| 会话平均时长 | - | 会话总时长除以会话总数 |
| 使用频次 | - | 会话总数除以活跃用户数 |
**UV 口径说明**:Native(Android/iOS/HarmonyOS/Flutter)看板与应用卡片的 UV 以设备稳定的匿名 ID 为口径,即 `COUNT(DISTINCT COALESCE(NULLIF(usr_anonymous_id, ''), NULLIF(usr_id, '')))`。匿名 ID 在用户登录后保持不变,因此匿名会话与同一用户后续的登录会话会计为同一用户;未开启匿名用户追踪时回退为 `usr_id` 口径。Web(浏览器)与小程序看板保持 `usr_id` 口径不变;**Electron 应用同样使用 Web 分析看板,但 UV 与 Native 看板一样以匿名 ID 为口径**——Electron SDK 不上报 `usr_id`(恒为空),稳定标识由主进程注入为 `usr_anonymous_id`。
### 性能指标阈值
| 指标 | 采集字段 | 良好 | 中等 | 差 |
| ------ | ----------------------------- | ------------- | ------------- | ------------- |
| 应用启动时间 | view\_app\_start\_time | 2s 以内 | 4s 以内 | 超过 4s |
| 帧率 | view\_refresh\_rate\_average | 55 FPS 以上 | 50 FPS 以上 | 低于 50 FPS |
| CPU 消耗 | view\_cpu\_ticks\_per\_second | 低于 40 ticks/s | 低于 60 ticks/s | 60 ticks/s 以上 |
| 内存使用 | view\_memory\_average | 低于 100 MB | 低于 200 MB | 200 MB 以上 |
| 峰值内存 | view\_memory\_max | 低于 200 MB | 低于 400 MB | 400 MB 以上 |
### 流畅度指标
| 指标 | 定义 | 采集字段 |
| ---- | ------------------ | -------------------- |
| 慢帧数 | 渲染耗时超过 16ms 的帧数 | - |
| 冻结帧数 | 渲染耗时超过 700ms 的帧数 | - |
| 长任务数 | 执行时间超过 100ms 的任务数量 | long\_task\_duration |
| 卡顿频率 | 平均每秒发生冻结的次数 | - |
### 稳定性指标
| 指标 | 计算方式 | 说明 |
| ----- | ------------- | ------------------------- |
| 崩溃次数 | 直接统计 | 由未处理的异常或信号引起的崩溃总次数 |
| 无崩溃率 | 1 减去崩溃会话占比 | 建议保持在 99% 以上 |
| ANR 率 | ANR 会话数除以总会话数 | UI 线程阻塞超过 5 秒时触发(Android) |
| 应用卡顿率 | 卡顿会话数除以总会话数 | 主线程无响应超过 250ms 时计入(iOS) |
## 延伸阅读
### SDK 接入与配置
了解如何在 Android 应用中集成 RUM SDK
了解如何在 iOS 应用中集成 RUM SDK
深入配置 Android RUM SDK 高级功能
深入配置 iOS RUM SDK 高级功能
了解 Android RUM SDK 收集的数据类型
了解 iOS RUM SDK 收集的数据类型
### 数据分析与监控
学习如何使用 RUM Explorer 深入分析数据
掌握错误追踪和调试技巧
理解错误聚合机制
# Web RUM 分析
Source: https://docs.flashduty.com/zh/rum/analytics/web
本文档详细介绍 Flashduty RUM 分析看板的功能和使用方法
## 概述
Flashduty RUM 分析看板提供了开箱即用的可视化仪表板,自动采集并分析用户会话、性能、资源、错误等多维度数据,助力您全面洞察应用真实运行状况,快速定位性能瓶颈与异常问题,持续优化用户体验。
分析看板主要包含以下四个分析维度:
关键指标一目了然
全面掌控应用体验
快速定位与诊断错误
精细化资源优化
## 概览
概览模块聚焦于应用多维度的核心指标:
| 指标类型 | 说明 |
| ----------- | ----------------------------------------------- |
| **流量指标** | 监控 PV(页面浏览量)、UV(独立访客数)、会话数,把握整体访问趋势 |
| **用户分布** | 结合地理位置、设备类型等信息,洞察用户来源与活跃区域 |
| **健康与性能指标** | 显示核心 Web 指标:LCP(最大内容绘制)、FID(首次输入延迟)、CLS(累积布局偏移) |
| **异常与错误** | 统计各类型错误率,快速发现潜在风险点 |
## 性能分析
性能分析模块专注于应用加载与交互体验的全链路监控:
* **页面性能**:监控 FCP、LCP、CLS 等页面加载核心指标的趋势与样本分布
* **长任务**:[长动画帧](https://developer.chrome.com/docs/web-platform/long-animation-frames#long-frames-api)渲染更新延迟超过 50 毫秒的情况
* **XHR 和 Fetch 请求**:分析接口的加载性能,定位慢接口
* **静态资源**:分析静态资源的加载耗时,定位应用加载时的性能瓶颈
有关显示数据的更多信息,请参阅 [数据收集](/zh/rum/others/data-collection)。
## 异常分析
异常分析模块提供全方位的错误监控与诊断能力:
* **页面错误率**:发生错误最多的页面,帮助您定位优先需要关注的页面
* **热门 Issue**:影响用户最多的 Issue 排行,详见 [异常聚合](/zh/rum/error-tracking/error-aggregation)
* **代码错误**:分类展示错误类型,详见 [异常追踪](/zh/rum/error-tracking/overview)
* **接口和资源错误**:监控哪些接口和静态资源产生的错误最多
## 资源分析
资源分析模块帮助您识别对应用影响最大的资源:
* **资源排行**:监控加载最多与最重的资源,识别优化重点
* **资源加载时序**:监控资源耗时趋势(DNS 解析、TCP 连接、加载耗时等)
* **XHR 和 Fetch 请求**:区分不同请求类型、方法和错误状态码的分布趋势
* **第三方资源**:资源地址(host)与当前页面地址(host)不匹配的资源被识别为第三方资源
### 流量分布
流量分布模块帮助您分析自有资源与第三方资源的请求情况,识别外部依赖对应用性能的影响。
该模块包含以下三个部分:
| 部分 | 说明 |
| -------- | ---------------------------------------------------------------------------- |
| **资源列表** | 按域名(Host)聚合展示资源的请求数量、P90/P50 耗时、请求成功率和资源提供商类别(自有资源或第三方)。支持按域名正则筛选和按资源提供商类别筛选 |
| **耗时趋势** | 以折线图展示自有资源与第三方资源的 P90 耗时对比趋势,帮助您判断第三方资源是否拖慢了整体加载速度 |
| **流量占比** | 以饼图展示各第三方域名的请求量占比,直观了解流量在第三方服务间的分布情况 |
您可以在资源列表中点击全屏按钮查看更详细的数据,并通过排序功能快速定位耗时最长或请求量最大的域名。
## 常见问题
可能有以下原因:
1. **连接复用 (Keep-Alive)**:当资源请求采用 keep-alive 方式保持连接时,DNS 查询和 TCP 连接过程只会在首次请求时发生,后续请求复用同一连接
2. **跨域加载资源**:如果资源以跨域方式加载且未配置相关头部信息,浏览器无法采集完整的性能数据(主要原因)
3. **浏览器兼容性**:极少数情况下,某些浏览器可能不支持 Performance API
1. **跨域加载资源**:如果资源以跨域方式加载且未设置跨域访问权限,浏览器将无法获取资源状态信息
2. **浏览器兼容性**:某些浏览器可能不支持 Performance API(极少见)
**1. 采集跨域资源的时序数据**
在跨域资源的 HTTP 响应头中添加:
```
Timing-Allow-Origin: *
```
详见 MDN 文档 [Resource Timing API](https://developer.mozilla.org/zh-CN/docs/Web/API/Performance_API/Resource_timing#cross-origin_timing_information)。
**2. 采集跨域资源的状态码**
在跨域资源的 HTTP 响应头中添加:
```
Access-Control-Allow-Origin: *
```
在引用资源的 HTML 标签中添加 `crossorigin="anonymous"`:
```html theme={null}
```
详见 MDN 文档 [Access-Control-Allow-Origin](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Reference/Headers/Access-Control-Allow-Origin) 和 [crossorigin 属性](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Reference/Attributes/crossorigin)。
**登录态用户识别**
对于需要用户登录的应用(如 SaaS 产品、会员系统、电商平台等),参考 [用户会话](/zh/rum/sdk/web/advanced-config#用户会话)。
**设备指纹识别**
对于无登录态的应用(如企业官网、营销页面等),推荐基于浏览器特征、设备信息等多维数据生成稳定的指纹并上报用户标识。
# Android
Source: https://docs.flashduty.com/zh/rum/error-tracking/erro-reporting/android
掌握 Android RUM SDK 的异常捕获机制,包括 Java/Kotlin 崩溃、NDK 崩溃、ANR 报告、手动上报和符号化配置
本文档介绍 Android RUM SDK 的异常捕获机制,帮助您监控和诊断 Android 应用中的崩溃和错误问题。
SDK 支持自动捕获 Java/Kotlin 崩溃、NDK 原生崩溃、ANR(应用无响应),同时提供手动错误上报和符号化堆栈跟踪功能。
## 异常类型
Android RUM 可以监控以下类型的异常:
### Java/Kotlin 崩溃
SDK 自动捕获未处理的 Java/Kotlin 异常,包括:
* 运行时异常(如 `NullPointerException`、`IndexOutOfBoundsException`)
* 未捕获的异常
* 应用崩溃
### NDK 崩溃(Native Crash)
若您的应用使用了原生代码(C/C++),SDK 支持捕获 NDK 崩溃并将其纳入异常追踪。
### ANR(应用无响应)
SDK 可以检测并报告 ANR 问题,帮助您发现主线程阻塞导致的用户体验问题。
### 自定义错误
除了自动捕获的异常外,您还可以使用 RUM SDK 手动上报自定义异常,用于跟踪业务逻辑错误等特定问题。
## 配置崩溃报告
### 基础配置
崩溃报告功能默认启用。确保您已按照 [SDK 接入指南](https://docs.flashduty.com/zh/flashduty/rum/android-sdk-integration) 完成基础 SDK 集成后,SDK 会自动捕获应用中的未处理异常。
### 添加 NDK 崩溃报告
若您的应用包含原生代码(C/C++),需要添加 NDK 崩溃报告模块来捕获原生崩溃。
在您的应用模块的 `build.gradle` 文件中添加 NDK 崩溃报告依赖:
```groovy build.gradle theme={null}
dependencies {
implementation "cloud.flashcat:dd-sdk-android-ndk:"
}
```
在 SDK 初始化后启用 NDK 崩溃报告:
```kotlin theme={null}
import com.datadog.android.ndk.NdkCrashReports
// 在 Datadog.initialize() 之后调用
NdkCrashReports.enable()
```
### 添加 ANR 报告
ANR(Application Not Responding)是指应用主线程被阻塞超过一定时间,导致应用无法响应用户输入的情况。
#### 启用 ANR 检测
在 RUM 配置中启用 ANR 检测:
```kotlin theme={null}
import com.datadog.android.rum.RumConfiguration
val rumConfig = RumConfiguration.Builder(applicationId)
.trackNonFatalAnrs(true) // 追踪非致命 ANR
.build()
```
ANR 检测会监控主线程的响应性。当检测到主线程阻塞超过阈值时,SDK 会自动记录 ANR 事件。
## 手动错误上报
通过 `addError` API,您可以手动上报已处理的异常、自定义错误或其他未被自动捕获的错误。
### 上报错误示例
```kotlin theme={null}
import com.datadog.android.rum.GlobalRumMonitor
import com.datadog.android.rum.RumErrorSource
// 上报带有上下文的错误
try {
riskyOperation()
} catch (e: Exception) {
GlobalRumMonitor.get().addError(
message = "操作失败",
source = RumErrorSource.SOURCE,
throwable = e,
attributes = mapOf(
"operation" to "riskyOperation",
"userId" to "12345"
)
)
}
```
### 错误来源类型
`RumErrorSource` 可选值:
| 值 | 描述 |
| ------------------------ | ---------- |
| `RumErrorSource.NETWORK` | 网络错误 |
| `RumErrorSource.SOURCE` | 源码错误 |
| `RumErrorSource.CONSOLE` | 控制台错误 |
| `RumErrorSource.LOGGER` | 日志错误 |
| `RumErrorSource.AGENT` | Agent 错误 |
| `RumErrorSource.WEBVIEW` | WebView 错误 |
| `RumErrorSource.CUSTOM` | 自定义错误 |
### 上报网络错误示例
```kotlin theme={null}
import com.datadog.android.rum.GlobalRumMonitor
import com.datadog.android.rum.RumErrorSource
fun onNetworkError(url: String, statusCode: Int, error: Throwable) {
GlobalRumMonitor.get().addError(
message = "网络请求失败: $url",
source = RumErrorSource.NETWORK,
throwable = error,
attributes = mapOf(
"url" to url,
"status_code" to statusCode,
"method" to "GET"
)
)
}
```
## 获取脱混淆的堆栈跟踪
如果您的应用启用了代码混淆(ProGuard/R8),上报的崩溃堆栈将被混淆。通过上传 mapping 文件,可以将混淆后的堆栈还原为原始的类名、方法名和行号。
### 配置 Gradle 插件
在应用模块的 `build.gradle` 文件中添加 Flashcat Android Gradle 插件:
```groovy build.gradle theme={null}
plugins {
id("cloud.flashcat.android-gradle-plugin") version "1.1.0"
}
```
配置上传任务所需的应用标识和上传目标。未配置时,插件会从 Android 构建配置读取应用版本和包名:
```groovy build.gradle theme={null}
flashcat {
site = "CN" // 可选,可选值:CN、STAGING,默认 CN
serviceName = "" // 可选,默认使用应用包名
versionName = "1.0.0" // 可选,默认读取 android.defaultConfig.versionName
}
```
API Key 通过 `FC_API_KEY` / `FLASHCAT_API_KEY` 环境变量、同名 Gradle 属性,或项目根目录的 `flashcat-ci.json` 提供。更多配置项请参阅 [源码映射 - 上传 Android 符号文件](/zh/rum/error-tracking/source-mapping#上传-android-符号文件)。
### 上传 Mapping 文件
配置完成后,在构建完成后手动运行上传任务,或将任务加入您的 CI 发布流程:
```bash theme={null}
./gradlew uploadMapping
```
例如,对于 `release` 变体:
```bash theme={null}
./gradlew uploadMappingRelease
```
### 上传 NDK 符号文件
如果您使用了 NDK 崩溃报告,还需要上传 NDK 符号文件以获取可读的原生堆栈:
```bash theme={null}
./gradlew uploadNdkSymbolFiles
```
### 插件配置选项
| 属性名 | 描述 |
| -------------------------------- | ------------------------------------------------------------- |
| `versionName` | 应用版本名称,默认读取 Android 构建配置中的 `versionName` |
| `serviceName` | 服务名称,默认使用应用包名 |
| `site` | 上传站点,可选值:`CN`、`STAGING`,默认 `CN` |
| `mappingFilePath` | 自定义 ProGuard/R8 mapping 文件路径,默认使用当前 variant 的 Android 构建产物 |
| `nonDefaultObfuscation` | 使用 DexGuard 等非默认混淆工具时设为 `true`,插件会为所有 variant 创建上传任务 |
| `additionalSymbolFilesLocations` | 额外 NDK 符号目录,目录结构需类似 `/path/to/location/obj/{arch}/libname.so` |
| `checkProjectDependencies` | 控制是否检查 Flashcat SDK 依赖。可选值:`none`、`warn`、`fail`;未配置时不检查 |
### Mapping 文件大小限制
Mapping 文件大小限制为 **500 MB**。如果文件过大,可以使用以下选项减小文件大小:
```groovy build.gradle theme={null}
flashcat {
mappingFileTrimIndents = true // 移除缩进,平均减少约 5% 的文件大小
mappingFilePackageAliases = [
"kotlinx.coroutines": "kx.cor",
"com.google.android.material": "material",
"com.google.gson": "gson"
]
}
```
使用 `mappingFilePackageAliases` 时,Flashcat 异常追踪中的堆栈将使用别名替代原始包名。建议仅对第三方依赖使用此选项。
## 追踪后台事件
默认情况下,只有在视图处于活动状态时发生的崩溃才会被追踪。如果您希望追踪应用在后台时发生的崩溃,可以启用后台事件追踪:
```kotlin theme={null}
import com.datadog.android.rum.RumConfiguration
val rumConfig = RumConfiguration.Builder(applicationId)
.trackBackgroundEvents(true)
.build()
```
追踪后台事件可能会产生额外的会话,这可能会影响计费。如有疑问,请联系 Flashcat 支持团队。
## 限制与注意事项
### 崩溃检测限制
* **SDK 初始化时机**:崩溃只有在 SDK 初始化之后才能被检测到。建议在 `Application.onCreate()` 中尽早初始化 SDK。
* **视图关联**:崩溃必须与一个 RUM 视图关联。若在视图显示前或应用被置于后台后发生崩溃,该崩溃可能不会被报告。可通过 `trackBackgroundEvents(true)` 缓解这一问题。
* **采样率影响**:只有被采样的会话中的崩溃才会被保留。如果会话采样率不是 100%,部分崩溃可能不会被报告。
### 符号化限制
* 确保 mapping 文件在每次发布新版本时都正确上传。
* 不同构建变体(如 debug/release)需要分别上传对应的 mapping 文件。
* NDK 符号文件需要包含调试信息才能正确符号化。
## 测试验证
### 验证 Java/Kotlin 崩溃
1. 在应用中添加测试代码触发崩溃:
```kotlin theme={null}
fun onEvent() {
throw RuntimeException("测试崩溃")
}
```
2. 运行应用并触发崩溃
3. 重启应用,等待 SDK 上传崩溃报告
4. 在 Flashcat 控制台的异常追踪模块中查看崩溃报告
### 验证 NDK 崩溃
1. 在原生代码中添加测试崩溃:
```cpp theme={null}
void crash() {
int* ptr = nullptr;
*ptr = 42; // 触发空指针崩溃
}
```
2. 从 Java/Kotlin 代码调用该原生方法
3. 重启应用,等待 SDK 上传崩溃报告
4. 确认堆栈是否已被正确符号化(显示函数名、文件名和行号)
### 验证 ANR
1. 在主线程执行耗时操作:
```kotlin theme={null}
fun blockMainThread() {
Thread.sleep(10000) // 阻塞主线程 10 秒
}
```
2. 触发该操作后尝试与应用交互
3. 检查 Flashcat 控制台是否收到 ANR 报告
## 错误数据结构
每条错误数据包含以下属性:
| 属性 | 类型 | 描述 |
| ---------------- | ------- | ---------------------------------------- |
| `error.source` | string | 错误来源(如 `source`、`network`、`custom`) |
| `error.type` | string | 错误类型或错误码(如 `NullPointerException`) |
| `error.message` | string | 错误消息 |
| `error.stack` | string | 错误堆栈跟踪 |
| `error.is_crash` | boolean | 是否为崩溃 |
| `context` | Object | 自定义上下文信息,通过 `addError` 的 `attributes` 传入 |
## 最佳实践
1. **尽早初始化 SDK**:在 `Application.onCreate()` 中初始化 SDK,确保能捕获尽可能多的崩溃。
2. **启用后台事件追踪**:如果您的应用有大量后台操作,建议启用 `trackBackgroundEvents`。
3. **正确上传符号文件**:
* 为每个发布版本上传对应的 mapping 文件
* 如果使用 NDK,同时上传 NDK 符号文件
* 在 CI/CD 流程中集成符号文件上传
4. **丰富错误上下文**:在手动上报错误时,附加业务相关的上下文信息(如用户 ID、操作类型)。
5. **过滤无关错误**:使用 `setErrorEventMapper` 过滤第三方 SDK 或无关的错误,减少噪音。
## 下一步
了解如何在异常追踪模块查看和分析 Issue
配置 Android SDK 的高级功能
# iOS
Source: https://docs.flashduty.com/zh/rum/error-tracking/erro-reporting/ios
掌握 iOS RUM SDK 的异常捕获机制,包括崩溃捕获、App Hangs、Watchdog 终止、手动上报和 dSYM 符号化
本文档介绍 iOS RUM SDK 的异常捕获机制,帮助您监控和诊断 iOS 应用中的崩溃和错误问题。
SDK 支持自动捕获应用崩溃、App Hangs(应用挂起)、Watchdog 终止,同时提供手动错误上报和 dSYM 符号化功能。
## 异常类型
iOS RUM 可以监控以下类型的异常:
### 应用崩溃
SDK 自动捕获未处理的异常和致命信号,包括:
* 未捕获的 Swift/Objective-C 异常
* 致命信号(如 `SIGSEGV`、`SIGABRT`)
* Mach 异常
### App Hangs(应用挂起)
当主线程被阻塞超过指定阈值时,SDK 会检测并报告 App Hang 事件,帮助您发现影响用户体验的卡顿问题。
### Watchdog 终止
iOS 系统的 Watchdog 机制会终止长时间无响应的应用。SDK 可以检测这类终止并报告为崩溃事件。
### 自定义错误
除了自动捕获的异常外,您还可以使用 RUM SDK 手动上报自定义异常,用于跟踪业务逻辑错误等特定问题。
## 配置崩溃报告
### 添加 Crash Reporting 模块
要启用崩溃报告功能,需要添加 `FlashcatCrashReporting` 模块。
#### Swift Package Manager
在 Xcode 中添加包依赖时,同时添加以下模块:
* `FlashcatCore`:核心 SDK
* `FlashcatRUM`:RUM 功能模块
* `FlashcatCrashReporting`:崩溃报告模块
### 初始化崩溃报告
在 SDK 初始化后启用崩溃报告:
```swift AppDelegate.swift theme={null}
import FlashcatCore
import FlashcatRUM
import FlashcatCrashReporting
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// 初始化 Flashcat SDK
Flashcat.initialize(
with: Flashcat.Configuration(
clientToken: "",
env: ""
),
trackingConsent: .granted
)
// 启用崩溃报告
CrashReporting.enable()
// 启用 RUM
RUM.enable(
with: RUM.Configuration(
applicationID: ""
)
)
return true
}
}
```
建议在 `application(_:didFinishLaunchingWithOptions:)` 中尽早初始化 SDK 和崩溃报告,以确保能捕获应用启动阶段的崩溃。
## 配置 App Hangs 检测
App Hang 是指主线程被阻塞导致应用无法响应用户输入的情况。SDK 可以检测这类问题并上报。
### 启用 App Hangs 追踪
在 RUM 配置中设置 `appHangThreshold` 参数:
```swift theme={null}
import FlashcatRUM
RUM.enable(
with: RUM.Configuration(
applicationID: "",
appHangThreshold: 0.25 // 250 毫秒
)
)
```
### App Hang 阈值说明
| 阈值设置 | 描述 | 适用场景 |
| ------ | -------------- | ----------- |
| `0.25` | 250 毫秒,检测轻微卡顿 | 对流畅度要求极高的应用 |
| `1.0` | 1 秒,检测明显卡顿 | 一般应用推荐值 |
| `nil` | 禁用 App Hang 检测 | 默认设置 |
**配置建议:**
* 设置过低的阈值可能会产生大量报告,建议根据应用实际情况调整
* 如果 App Hang 导致应用被 Watchdog 终止,该事件会被标记为崩溃类型
## 配置 Watchdog 终止追踪
iOS 的 Watchdog 机制会终止长时间无响应的应用。SDK 可以在下次应用启动时检测并报告这类终止。
### 启用 Watchdog 终止追踪
```swift theme={null}
import FlashcatRUM
RUM.enable(
with: RUM.Configuration(
applicationID: "",
trackWatchdogTerminations: true
)
)
```
### Watchdog 终止检测条件
SDK 会在以下条件全部满足时将上次应用终止判定为 Watchdog 终止:
* 应用不是被用户强制退出
* 上次运行未发生崩溃或 fatal error
* 应用未进行升级
* 应用在前台且正在响应事件
## 手动错误上报
通过 `addError` API,您可以手动上报已处理的异常、自定义错误或其他未被自动捕获的错误。
### 上报错误示例
```swift theme={null}
import FlashcatRUM
// 上报带有上下文的错误
RUMMonitor.shared().addError(
message: "网络请求失败",
type: "NetworkError",
source: .network,
attributes: [
"url": "https://api.example.com",
"status_code": 500,
"userId": "12345"
]
)
```
### 错误来源类型
| 来源 | 描述 |
| ---------- | ---------- |
| `.source` | 源码错误 |
| `.network` | 网络错误 |
| `.webview` | WebView 错误 |
| `.console` | 控制台错误 |
| `.custom` | 自定义错误 |
### 上报异常对象示例
```swift theme={null}
import FlashcatRUM
do {
try riskyOperation()
} catch {
RUMMonitor.shared().addError(
error: error,
source: .source,
attributes: [
"operation": "riskyOperation",
"timestamp": Date().timeIntervalSince1970
]
)
}
```
## 获取符号化的堆栈跟踪
崩溃报告中的堆栈默认为内存地址。通过上传 dSYM 符号文件,可以将这些地址转换为可读的函数名、文件名和行号。
### 什么是 dSYM 文件
dSYM(Debug Symbol)文件包含了应用的调试符号信息,用于将崩溃堆栈中的内存地址映射到源代码位置。
### 使用命令行工具上传 dSYM
```bash theme={null}
npm install -g @flashcat/flashcat-ci
```
```bash theme={null}
export FLASHCAT_API_KEY=""
flashcat-ci dsyms upload /path/to/dSYMs
```
**支持的文件格式:**
* `.dSYM` 目录
* `.dSYM.zip` 压缩包
* 包含多个 dSYM 的 `.zip` 压缩包
### 在 CI/CD 中集成 dSYM 上传
#### Xcode Build Phase 脚本
在 Xcode 项目的 Build Phases 中添加 Run Script:
```bash theme={null}
#!/bin/bash
if [ "$CONFIGURATION" = "Release" ]; then
export FLASHCAT_API_KEY=""
flashcat-ci dsyms upload "${DWARF_DSYM_FOLDER_PATH}"
fi
```
#### Fastlane 集成
在 `Fastfile` 中添加上传步骤:
```ruby theme={null}
lane :upload_dsyms do
ENV["FLASHCAT_API_KEY"] = ""
sh("flashcat-ci dsyms upload #{lane_context[SharedValues::DSYM_OUTPUT_PATH]}")
end
```
### Bitcode 应用的 dSYM
如果您的应用启用了 Bitcode,Apple 会在 App Store 处理时重新编译应用,生成新的 dSYM 文件。您需要从 App Store Connect 下载这些 dSYM 并上传。
#### 下载 Bitcode dSYM
访问 [App Store Connect](https://appstoreconnect.apple.com) 并登录您的账号。
进入您的应用 → 活动 → 选择需要下载 dSYM 的构建版本。
点击「下载 dSYM」按钮,下载完成后使用 flashcat-ci 工具上传。
### dSYM 文件限制
* 每个 dSYM 文件大小限制为 **2 GB**
* 仅真实设备上的崩溃支持符号化,模拟器生成的崩溃不支持
## 追踪后台事件
默认情况下,只有在视图处于活动状态时发生的崩溃才会被追踪。如果您希望追踪应用在后台时发生的崩溃,可以启用后台事件追踪:
```swift theme={null}
import FlashcatRUM
RUM.enable(
with: RUM.Configuration(
applicationID: "",
trackBackgroundEvents: true
)
)
```
追踪后台事件可能会产生额外的会话,这可能会影响计费。如有疑问,请联系 Flashcat 支持团队。
## 限制与注意事项
### 崩溃检测限制
* **SDK 初始化时机**:崩溃只有在 SDK 和 `CrashReporting.enable()` 调用之后才能被检测到。建议尽早初始化。
* **调试器干扰**:在 Xcode 调试器连接时,崩溃会被调试器捕获而非 SDK。测试崩溃报告时,请在不连接调试器的情况下运行应用。
* **崩溃报告上传时机**:崩溃报告会在应用下次启动时上传,因此崩溃发生后需要重新启动应用才能看到报告。
### 符号化限制
* 仅真实设备上的崩溃支持符号化,模拟器生成的崩溃不支持。
* 每个发布版本都需要上传对应的 dSYM 文件。
* 如果使用 Bitcode,需要从 App Store Connect 下载并上传重新生成的 dSYM。
### App Hang 检测限制
* App Hang 检测仅在应用处于前台时有效。
* 检测精度取决于阈值设置,过低的阈值可能产生大量误报。
## 测试验证
### 验证崩溃报告
1. **不连接调试器运行应用**:从 Xcode 停止应用,然后从设备上直接启动。
2. **触发测试崩溃**:
```swift theme={null}
func triggerTestCrash() {
fatalError("测试崩溃")
}
```
3. **重启应用**:崩溃发生后,从设备上重新启动应用,等待 SDK 上传崩溃报告。
4. **查看报告**:在 Flashcat 控制台的异常追踪模块中查看崩溃报告。
### 验证 App Hang
1. 在主线程执行耗时操作:
```swift theme={null}
func blockMainThread() {
Thread.sleep(forTimeInterval: 5) // 阻塞主线程 5 秒
}
```
2. 触发该操作后尝试与应用交互。
3. 检查 Flashcat 控制台是否收到 App Hang 报告。
### 验证符号化
1. 确保已上传对应版本的 dSYM 文件。
2. 触发崩溃并查看报告。
3. 确认堆栈中显示的是函数名、文件名和行号,而非纯内存地址。
## 错误数据结构
每条错误数据包含以下属性:
| 属性 | 类型 | 描述 |
| ---------------- | ------- | ---------------------------------------- |
| `error.source` | string | 错误来源(如 `source`、`network`、`custom`) |
| `error.type` | string | 错误类型(如 `NSException`、`Signal`) |
| `error.message` | string | 错误消息 |
| `error.stack` | string | 错误堆栈跟踪 |
| `error.is_crash` | boolean | 是否为崩溃 |
| `context` | Object | 自定义上下文信息,通过 `addError` 的 `attributes` 传入 |
## 最佳实践
1. **尽早初始化 SDK**:在 `application(_:didFinishLaunchingWithOptions:)` 中尽早调用 `Flashcat.initialize()` 和 `CrashReporting.enable()`。
2. **正确上传 dSYM**:
* 为每个发布版本上传对应的 dSYM 文件
* 在 CI/CD 流程中集成 dSYM 上传
* 如果使用 Bitcode,及时从 App Store Connect 下载并上传 dSYM
3. **合理设置 App Hang 阈值**:根据应用性能要求设置合适的阈值,避免过多误报。
4. **丰富错误上下文**:在手动上报错误时,附加业务相关的上下文信息(如用户 ID、操作类型)。
5. **测试时断开调试器**:验证崩溃报告功能时,确保不连接 Xcode 调试器。
## 下一步
了解如何在异常追踪模块查看和分析 Issue
配置 iOS SDK 的高级功能
# Web 异常上报
Source: https://docs.flashduty.com/zh/rum/error-tracking/erro-reporting/web
了解 RUM 的异常上报机制
本文档介绍异常类型、捕获机制、手动上报方法、React 集成以及上报的异常数据结构定义。
## 异常类型
RUM 可以监控以下类型的异常:
包括代码语法错误、运行时异常和未处理的 Promise 异常等。这些问题可能导致页面功能失效,严重影响用户体验。
监控与后端服务或第三方 API 的通信问题:
* XHR/Fetch 请求失败
* 请求超时
* 跨域(CORS)错误
* HTTP 4xx/5xx 状态码
监控网页资源加载失败的情况:
* 图片加载失败
* 脚本加载失败
* 样式表加载失败
* 字体文件加载失败
除了自动捕获的异常外,您还可以使用 RUM SDK 手动上报自定义异常,用于跟踪业务逻辑错误等特定问题。
## 上报方式
### 自动错误捕获
RUM SDK 自动捕获以下类型的浏览器错误:
| 错误类型 | 说明 |
| --------------- | ---------------------------------------------------- |
| 未捕获的异常 | 运行时抛出的 JavaScript 异常(如 `TypeError`、`ReferenceError`) |
| 未处理的 Promise 拒绝 | 未被 `.catch()` 处理的 Promise 错误 |
| 网络错误 | XHR 或 Fetch 请求失败(如 4xx、5xx 状态码或网络中断) |
| React 渲染错误 | React 组件渲染期间的异常(需配合错误边界) |
* 自动捕获的错误默认包含堆栈跟踪、错误消息和来源信息。
* 来自浏览器扩展或第三方脚本的错误(如 `network` 来源)会被过滤,避免数据污染。
### 手动错误上报
通过 `addError` API,您可以手动上报已处理的异常、自定义错误或其他未被自动捕获的错误。
**适用场景:**
* 记录业务逻辑中的已处理错误
* 附加上下文信息(如用户 ID、页面状态)以便问题排查
* 监控第三方服务或异步操作的异常
```javascript 上报自定义错误 theme={null}
// 上报带有上下文的自定义错误
const error = new Error("登录失败");
window.FC_RUM.addError(error, {
pageStatus: "beta",
userId: "12345",
action: "login_attempt",
});
```
```javascript 上报网络错误 theme={null}
fetch("https://api.example.com/data").catch((error) => {
window.FC_RUM.addError(error, {
requestUrl: "https://api.example.com/data",
method: "GET",
});
});
```
```javascript 上报已处理异常 theme={null}
try {
// 可能抛出异常的业务逻辑
riskyOperation();
} catch (error) {
window.FC_RUM.addError(error, {
operation: "riskyOperation",
timestamp: Date.now(),
});
}
```
### React 错误边界集成
RUM 支持通过 React [错误边界](https://legacy.reactjs.org/docs/error-boundaries.html)捕获组件渲染错误,并将错误信息上报。您可以在 `componentDidCatch` 中调用 `addError` API,附加组件堆栈信息以便调试。
```javascript theme={null}
class ErrorBoundary extends React.Component {
componentDidCatch(error, info) {
const renderingError = new Error(error.message);
renderingError.name = "ReactRenderingError";
renderingError.stack = info.componentStack; // 组件堆栈
renderingError.cause = error; // 原始错误
window.FC_RUM.addError(renderingError, {
component: this.props.componentName || "Unknown",
version: "1.0.0",
});
}
render() {
return this.props.children;
}
}
```
```jsx theme={null}
```
## 错误数据结构
每条错误数据包含以下属性,用于描述错误详情和上下文:
错误来源(如 `console`、`network`、`custom`、`source`、`report`)。微信小程序 SDK 还会上报 `app`(来自 `wx.onError`)和 `promise`(来自 `wx.onUnhandledRejection`)两个值,详情见[微信小程序数据采集](/zh/rum/sdk/wechat-miniprogram/data-collection)。
错误类型或错误码(如 `TypeError`、`NetworkError`)
简洁的可读性强的错误消息
错误堆栈跟踪或补充信息
提供额外上下文的关联错误列表(可选)
自定义上下文信息(如页面状态、用户 ID),通过 `addError` 传入
## 错误过滤与配置
为确保错误数据的准确性和相关性,RUM 应用以下过滤规则:
* 仅处理 `source` 为 `custom`、`source`、`report` 或 `console` 的错误
* 忽略来自浏览器扩展、第三方脚本或 `network` 来源的无关错误
错误必须包含堆栈跟踪信息,否则可能被忽略
使用 `beforeSend` 回调自定义错误处理逻辑,过滤或修改错误数据
### 自定义错误过滤示例
```javascript theme={null}
window.FC_RUM.init({
beforeSend: (event) => {
if (event.type === "error") {
// 忽略特定错误消息
if (event.error.message.includes("ThirdPartyScript")) {
return false; // 丢弃该错误
}
// 添加全局上下文
event.context = { ...event.context, appVersion: "2.1.0" };
}
return true;
},
});
```
## 常见问题
* 确认堆栈跟踪是否完整,或自定义指纹是否冲突
* 检查 `sourcemap` 是否正确上传,若未上传,堆栈可能无法正确解析
使用 `beforeSend` 回调过滤特定错误来源或消息:
```javascript theme={null}
beforeSend: (event) => {
if (event.error.source === "network") return false;
return true;
};
```
* 确保 `fingerprint` 属性正确设置,且值为字符串
* 检查 `beforeSend` 回调是否被正确调用
## 最佳实践
在 `addError` 中附加业务相关上下文(如用户 ID、操作类型),便于问题定位。
示例:`{ userId: "12345", action: "submit_form" }`
为关键 React 组件配置错误边界,确保渲染错误被捕获。记录组件名称和版本,便于追踪问题。
使用采样率或 `beforeSend` 过滤低价值错误,避免数据过载。优先监控影响用户体验的关键错误。
在「分析看板」-「异常分析」Tab 查看错误数据趋势和分布,解决重点异常问题。
## 下一步
了解如何在异常追踪模块查看和分析 Issue
# 异常聚合
Source: https://docs.flashduty.com/zh/rum/error-tracking/error-aggregation
了解 Flashduty RUM 的异常聚合机制,提高 Issue 定位效率。
当新错误事件发生时,Flashduty 采用三步聚合策略将错误聚合为 Issue,有效减少需要处理的错误数量。
## 聚合流程
获取错误事件的指纹,并与现有 Issue 的指纹比较
如果新事件与现有某个 Issue 共享相同指纹,则自动归入该 Issue
如果指纹未匹配,则利用机器学习模型分析错误相似度,将事件归入相似度最高的 Issue,或在相似度过低时创建新的 Issue。
**Android NDK 原生崩溃例外:** NDK 原生崩溃(`source_type` 含 `ndk` 或堆栈中存在应用层原生帧)会跳过此步骤的机器学习相似度分析,完全依赖步骤一的确定性指纹进行聚合。这是因为 NDK 崩溃的错误消息(如 `signal: SIGSEGV`)几乎完全相同,若走相似度分析会将来自不同代码位置的崩溃错误地合并为同一 Issue;而帧感知指纹能够精确区分不同的崩溃点。
**Flutter 原生崩溃按真实平台处理:** Flutter 应用上报的原生崩溃 `source` 为 `flutter`,聚合时会按 `source_type`(`ndk`、`android`、`ios`)解析出真实平台。其中 `source_type` 为 `ndk`(或堆栈中存在应用层原生帧)的崩溃与 Android NDK 崩溃一致,同样跳过机器学习相似度分析、使用原生帧指纹聚合;`source_type` 为 `ios` 的崩溃仍走消息指纹,与独立 iOS 应用的行为相同。
## 默认指纹
Flashduty 默认启用异常聚合,无需额外配置即可开始工作。Browser SDK 会自动收集错误数据并进行聚合。
在 HTML 文件中引入 Flashduty Browser SDK:
```html theme={null}
```
初始化 SDK 时,指定应用 ID 和环境:
```javascript theme={null}
window.FLASHCAT_RUM.init({
applicationId: "rum-application-id",
environment: "production",
version: "1.0.0",
});
```
### 指纹计算规则
当错误事件没有携带指纹时,Flashduty 基于以下错误属性自动计算指纹:
| 属性 | 说明 |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `service` | 错误发生的服务 |
| `env` | 错误发生的环境 |
| `error.type` | 错误的类型分类 |
| `error.message` | 错误的描述文本。对于 Android NDK 原生崩溃,此分量会附加堆栈中最顶层的应用层原生帧信息,格式为 `\|native::`(例如 `signal: SIGSEGV\|native:libmyapp.so:crash_func+48`)。系统库帧(`libc.so`、`libart.so` 等)和伪映射(`[vdso]`、`[stack]`)会被跳过,以确保同一崩溃位置在不同运行时始终产生相同指纹。 |
为提高聚合准确性,Flashduty 会去除堆栈帧中的变量属性,如版本号、ID、日期等动态参数。
## 自定义指纹
若默认聚合无法满足需求,您可以通过提供自定义指纹(fingerprint)完全控制错误的聚合行为。
自定义指纹的优先级高于默认指纹。
在手动报告错误时,通过 `addError` 添加自定义指纹:
```javascript theme={null}
window.FLASHCAT_RUM.addError(new Error("My error message"), {
source: "custom",
fingerprint: "my-custom-grouping-fingerprint",
});
```
通过 `beforeSend` 回调动态设置指纹:
```javascript theme={null}
window.FLASHCAT_RUM.init({
applicationId: "rum-application-id",
environment: "production",
beforeSend: (event) => {
if (event.type === "error") {
event.error.fingerprint = "my-custom-grouping-fingerprint";
}
return true;
},
});
```
* 自定义 fingerprint 必须为字符串类型
* 相同服务中具有相同 fingerprint 的错误将被归入同一 Issue
* 不同服务的错误即使 fingerprint 相同也会被归入不同 Issue
* `beforeSend` 回调还可用于过滤无关错误(如第三方脚本错误)
## Web 特定注意事项
上传 `sourcemap` 文件以解码压缩后的堆栈跟踪,确保聚合后的错误堆栈可映射到原始源代码。
```bash theme={null}
flashcat-cli sourcemaps upload \
--service my-service \
--release-version 1.0.0 \
--minified-path-prefix /assets \
--api-key your-api-key \
./dist
```
默认情况下,Flashduty 会过滤来自浏览器扩展或第三方脚本的错误(如 `network` 来源),以减少噪声。
可通过 `beforeSend` 进一步自定义过滤规则:
```javascript theme={null}
beforeSend: (event) => {
if (
event.error.source === "network" &&
event.error.message.includes("ThirdPartyScript")
) {
return false; // 丢弃该错误
}
return true;
};
```
## 查看聚合结果
在 Flashduty 平台,导航至「异常追踪」,查看聚合后的 Issue 列表。
也可以从应用列表直达:应用卡片上的 **Issue** 数字可以点击,点击后跳转到该应用的异常追踪列表,并自动锁定与卡片一致的口径——最近 24 小时、状态为「全部」,同时清除上次遗留的筛选条件,因此列表里的条数与卡片上的数字一致。
每个 Issue 包含:
| 内容 | 说明 |
| --------- | --------------------------- |
| 错误消息和堆栈跟踪 | 若上传了 `sourcemap`,会显示原始源代码位置 |
| 用户会话时间线 | 触发错误的操作路径 |
| 元数据 | 浏览器类型、版本号等 |
## 下一步
了解 Issue 状态流转机制
# Issue 概览与详情
Source: https://docs.flashduty.com/zh/rum/error-tracking/error-viewing
了解 Flashduty RUM 如何将相似错误聚合为 Issue,并查看发生记录、堆栈、影响用户和关联上下文。
错误上报后可在异常追踪模块查看 Issue。在 Flashduty RUM 中,一个 Issue 是由一组相似错误组成的,这些错误通常与同一个 bug 相关。
详细的聚合规则请参阅 [异常聚合](./error-aggregation)。
## Issue 信息概览
Issue 浏览器中列出的每个条目包含以下信息:
| 信息项 | 描述 |
| ----------- | ------------- |
| 错误类型和错误消息 | Issue 的核心标识信息 |
| 错误发生的文件路径 | 定位错误来源 |
| 服务名称 | 关联的服务 |
| 错误原因 | 系统推断的可能根因 |
| 问题是否有复现 | 标识已解决问题是否再次出现 |
| 首次和最后出现时间 | Issue 生命周期信息 |
| 发生次数图表 | 随时间变化的趋势 |
| 所选时间段内的发生次数 | 统计数据 |
## Issue 状态
Issue 有 4 种状态,流转方式如下:
| 状态 | 说明 |
| ------- | ----------- |
| **待处理** | 新发现的问题,需要关注 |
| **处理中** | 已确认并正在修复的问题 |
| **已解决** | 问题已修复 |
| **已忽略** | 无需处理的问题 |
问题复现相关流转逻辑请参阅 [Issue 状态](./issue-status)。
## 筛选与排序
浏览器右上角显示时间轴,允许您显示在选定时间段内发生错误的 Issue。您可以:
* 从下拉菜单中选择预设范围
* 直接修改时间
* 输入自然语言进行筛选
| 排序选项 | 说明 |
| ----- | ------------------- |
| 更新时间 | 根据问题更新时间排序(默认) |
| 创建时间 | 根据首次发现时间排序 |
| 发生次数 | 根据所选时间范围内错误的总发生次数排序 |
| 影响会话数 | 根据受影响的 RUM 会话数量排序 |
Flashduty RUM 自动为您的 Issue 建立预定义的属性索引,并创建对应的筛选器。
支持的属性包括:
| 属性 | 描述 |
| ------- | ---------------------------------- |
| 错误原因 | 错误发生时可能的根因类型 |
| 环境 | Issue 上报时的 env 字段 |
| 服务 | Issue 上报时的 service 字段 |
| 错误类型 | 上报的 error 事件中的 error.type 字段 |
| 错误信息 | error 事件中的 error.message 字段,支持模糊匹配 |
| IssueID | Issue 聚合时的 ID,多个 ID 之间可用逗号分割 |
| 问题复现 | 已解决的问题如果再次发生,则 Issue 会被标记为复现 |
| 指纹 | Issue 聚合时的指纹信息,多个指纹之间可用逗号分割 |
## 错误原因分类
Flashcat 在每次创建 Issue 时会为其添加错误发生可能产生的错误原因分类,帮助提升故障定位的效率。
| 错误原因 | 说明 |
| -------- | ------------------------- |
| 代码错误 | 由代码缺陷导致的错误 |
| 非法对象访问 | 代码访问了 null 或 undefined 对象 |
| 无效参数 | 使用无效参数调用函数 |
| 网络错误 | 服务器响应时间过长或网络速度慢 |
| API 请求失败 | API 端点返回了错误状态码 |
| 未知错误 | 无法定位该错误类型 |
当鼠标在错误原因分类上 hover 时,系统会结合 AI 能力进一步给出推断的根因和修复建议。
### 分类原理
系统采用两层分析机制对错误进行分类:
**第一层:模式匹配**
系统首先通过规则引擎按优先级依次检查错误类型和错误消息,首个匹配的规则决定分类结果:
| 检查顺序 | 匹配条件 | 分类结果 |
| ---- | ------------------------------------------------------------------ | -------- |
| 1 | 错误消息包含 "Unexpected token ... is not valid JSON" | 无效参数 |
| 2 | 关联资源的 HTTP 状态码为 4xx 或 5xx | API 请求失败 |
| 3 | 错误类型包含 "Network" 或 "AbortError" | 网络错误 |
| 4 | 错误类型包含 "Syntax"、"Reference"、"Range"、"URI" 或 "Eval" | 代码错误 |
| 5 | 错误类型为 TypeError 且消息匹配空值访问模式(如 "Cannot read property of undefined") | 非法对象访问 |
| 6 | 错误消息匹配无效参数模式(如 "invalid argument"、"unexpected token") | 无效参数 |
| 7 | 错误消息包含 "API ERROR:" 或许可证相关错误 | API 请求失败 |
| 8 | 错误消息包含网络连接相关关键词(如 "timeout"、"connection"、"dns") | 网络错误 |
| 9 | 以上均未匹配 | 未知错误 |
**第二层:AI 推断**
当模式匹配结果为「未知错误」时,系统会调用 AI 模型进行深度分析。AI 模型会结合以下信息进行判断:
* **错误消息**:错误的描述文本
* **堆栈信息**:完整的调用堆栈
* **平台类型**:浏览器/JavaScript、Android/Kotlin/Java、iOS/Swift/Objective-C、微信小程序等
AI 会输出错误分类和简要的原因解释(不超过 100 字)。推断结果在 Issue 卡片上以 hover 提示的形式展示,帮助您快速理解错误的根因。
## 问题复现
问题复现(Regression)指的是之前修复的 bug 再次出现。
如果一个错误被标记为已解决,但在后续(version 不同)又产生了相同的错误,则该 Issue 的状态会从结束态重新打开,并标记为「问题复现」。
## Issue 详情
Issue 列表支持两种查看模式:侧栏模式和全屏模式。默认以侧栏方式打开详情面板,您也可以点击展开按钮切换到全屏模式,获得更宽敞的查看空间和更完整的数据展示。
点击任何 Issue 可以打开详情面板,查看更多信息。
面板上部显示 Issue 的基础信息,如状态、错误原因等。您还可了解 Issue 的生命周期:首次和最后出现日期、持续时间,以及时间内的错误发生次数(按照一定时间粒度聚合)。
在标签分布区块可按照各种维度查看该 Issue 下不同标签所占比重,从而快速判断问题影响范围,辅助定位根因。
目前支持 `view_name`、`browser_name`、`version`、`env` 等标签。
默认展示当前 Issue 发生期间最近一次上报的错误信息作为错误样例,您也可通过导航条进行切换。
对于 Native 崩溃,样例导航列表中的每条样例都会标注符号化状态(「已解析」/「未解析」徽标)。当最新一条样例尚未解析、而更早的样例可以符号化时,详情会自动切换到可符号化的样例,并提示「已自动切换到可符号化的样例(最新一条尚未解析)」;点击「回到最新」可切回最新上报的样例。
查看错误的上下文信息和堆栈信息。如果已上传对应的 SourceMap、Android mapping 文件、iOS dSYM 文件或 Flutter 符号文件,您可以看到映射还原后的原始源码位置和代码片段。
在「应用管理」-「源码管理」可查看已上传的源码信息,详见 [源码映射](./source-mapping)。
Native 平台(Android/iOS)的错误堆栈展示针对移动端特点进行了专门设计,提供以下能力:
**Pretty / Raw 模式切换**
* **Pretty 模式**:结构化展示堆栈信息,自动区分应用帧(app frames)和第三方帧(third-party frames),第三方帧默认折叠,突出显示您自己的代码
* **Raw 模式**:展示原始堆栈文本,方便复制和在外部工具中分析
**符号化状态**
如果已上传对应版本的符号文件(Android mapping 或 iOS dSYM),堆栈中的混淆地址会被自动还原为可读的函数名、文件名和行号。未符号化时,系统会提示您上传符号文件,并提供直达「源码管理」和上传工具的链接。
符号化结果会被缓存。如果为一条已经出现过的崩溃补传了符号文件,点击提示条或「本条崩溃所需符号」区块中的「重新解析」按钮,即可跳过缓存强制重新执行符号化(重新拉取 dSYM 并完整还原),并刷新当前堆栈,无需等待新的崩溃上报。
**线程堆栈(Threads)**
Native 崩溃通常涉及多个线程。线程面板展示崩溃时所有线程的堆栈信息,支持:
* 查看线程总数和当前展示的线程数
* 展开/折叠所有线程
* 每个线程内独立区分应用帧和第三方帧,第三方帧可按需展开查看
* 崩溃线程的堆栈会被优先展示
**Binary Images(iOS)**
对于 iOS 崩溃,还可以查看崩溃时加载的 Binary Images(二进制镜像)列表,包含镜像名称、地址范围和 UUID 等信息,用于辅助离线符号化分析。
**本条崩溃所需符号(非系统库)**
当崩溃事件携带非系统二进制镜像时(iOS、Electron 等通过二进制镜像还原地址的 Native 崩溃,含 Flutter 的 iOS 原生崩溃),堆栈上方会展示「本条崩溃所需符号(非系统库)」区块,列出本条崩溃引用的所有非系统二进制镜像及其符号化状态:
* 区块标题汇总为「已解析数/总数 已解析」;全部已解析时默认折叠为一行摘要,存在未解析镜像时默认展开
* 每个镜像一行,展示镜像名称、UUID 以及「已解析」/「未解析」徽标,并提供复制 UUID 的按钮
* 点击「在符号表中查找」跳转到「源码映射」页面,并按该镜像的 UUID 预筛选符号表
* 未解析的镜像提供「去上传」链接,直达「源码映射」页面的上传入口
* 未解析时也可以点击区块中的「重新解析」按钮,强制重新符号化并刷新堆栈
**Flutter 支持**
Flutter 原生崩溃(`source_type` 为 `ndk`、`android` 或 `ios`)携带线程堆栈和 Binary Images,与 Android/iOS 原生崩溃一样使用上述 Native 渲染展示;Dart 异常则按堆栈中的 build\_id 匹配已上传的 Flutter 符号文件,进行符号化还原。
详细的符号文件上传流程请参阅 [源码映射](./source-mapping)。
查看当前错误示例所属的 Session 事件总数,以及该异常发生前后用户的资源访问情况和操作情况。
当前最多展示包含当前 Error 事件在内的 20 条上下文信息,后续您可在 Session 查看器模块查看更多日志信息。
如果该会话已采集了回放数据,您可以直接点击「查看回放」按钮跳转到会话重放页面,从用户视角重现错误发生时的完整操作路径。
异常事件在上报时会携带一系列属性,您可在属性区块查看当前的 Session、视图、用户等各类信息,方便排查问题。
## 异常告警
在问题发生时立即发现它,让您有机会在问题变得严重之前主动识别和修复它。
选中应用卡片后进行编辑
打开「告警」开关
选择通知的协作空间
具体告警配置说明请参阅 [Issue 告警](./issue-alerts)。
## 最佳实践
便于在生产环境定位问题
配置用户相关信息,提供更好的错误上下文
为错误配置合理的协作空间和分派策略
定期检查错误报告,发现潜在问题
利用团队所有权功能确保问题能够快速分配给相关团队
密切关注已解决问题的潜在回归
## 下一步
配置源码映射
了解聚合机制
管理 Issue 状态
# Issue 告警
Source: https://docs.flashduty.com/zh/rum/error-tracking/issue-alerts
了解 Flashduty RUM Issue 如何触发告警,以及如何配置告警分级和数据过滤
Flashduty RUM 自动将 SDK 上报的错误事件聚合为 Issue,帮助您优先处理最具影响力的问题,减少服务停机时间和用户沮丧感。
您可以在控制台每日巡检 Issue,也可以配置告警通知,在问题发生时第一时间感知。Flashduty RUM 的告警能力包括:
* **告警通知**:将 Issue 以告警事件投递到 Flashduty 协作空间,通过分派策略通知值班人员
* **Webhook 投递**:将 Issue 告警直接 POST 到您的接收端,适合不启用 On-call 的 RUM 私有化环境或自建通知链路
* **告警分级**:根据错误属性(如用户、页面、环境等)自定义告警优先级
* **数据过滤**:在 Error 聚合为 Issue 之前过滤噪音数据,减少无效告警
## 开启告警
前往「应用管理」,选择目标应用,点击左侧「告警设置」
开启告警开关,并选择投递方式:Flashduty 协作空间或 Webhook
如果选择 Flashduty 协作空间,告警的通知规则遵循协作空间下的分派策略,您可以为团队设定值班人员,在告警发生时分派给值班人
如果选择 Webhook,填写您的接收端 URL。保存前可以点击「发送测试事件」验证地址是否可访问、接收端是否能解析示例告警事件
只有选择「Flashduty 协作空间」投递时才需要开通 On-call 服务。选择 Webhook
投递时,RUM 会直接向您配置的 URL 发送告警事件,不会创建或使用 On-call
集成。
## 投递方式
| 投递方式 | 适用场景 | 配置要求 | 后续处理 |
| -------------- | --------------------------------------------- | ------------------------------------------ | ------------------------------------------------------- |
| Flashduty 协作空间 | 需要在 Flashduty 内完成故障协同、值班分派、通知升级和告警处理 Pipeline | 选择一个或多个协作空间;如果未选择协作空间,告警不会被投递 | Issue 告警进入对应协作空间,继续走集成配置、降噪配置和分派策略 |
| Webhook | RUM-only 私有化部署、自建通知系统,或希望把 Issue 告警直接送到外部接收端 | 填写可访问的 Webhook 地址。开启告警并选择 Webhook 时,地址不能为空 | RUM 直接向该 URL POST 示例或真实告警事件;钉钉、企业微信等机器人需要您的接收端做格式转换后再转发 |
Webhook 配置区提供「发送测试事件」按钮。测试会向当前填写的 URL 发送一条示例告警事件,并返回 HTTP 状态码和结果信息,便于您在保存前确认网络连通性和接收端解析逻辑。
## 告警触发条件
| 触发条件 | 说明 |
| --------------- | ------------------------------------------------------------------------------------------------ |
| **新的 Issue** | 错误事件导致新的 Issue 出现,会触发告警事件 |
| **Issue 更新** | 持续有错误事件合入一个未关闭(待处理、处理中)的 Issue,且距离上一个触发告警事件超过 24 小时,将会重新触发告警事件 |
| **Issue 重开** | 新的错误合入已关闭的 Issue,导致 Issue 被重新打开,即问题复现 |
| **Issue 优先级升级** | 当高优先级的错误事件进入低优先级的 Issue 时,Issue 优先级会自动升级并触发新的告警事件。例如,一个 P2 级别的 Issue 收到匹配 P0 规则的错误,会升级为 P0 并触发告警 |
* Issue 触发的是一个告警事件,实际投递位置取决于您在告警设置中选择的投递方式
* 选择 Flashduty 协作空间时,是否触发通知取决于协作空间下的集成配置、降噪配置以及分派策略
* 选择 Webhook 时,RUM 直接向 Webhook URL 投递事件;后续通知、格式转换和重试策略由您的接收端负责
* 当 Issue 关闭时,系统会触发关闭类型的告警事件;如果走协作空间投递,其关联的故障可能会自动恢复
## 告警严重程度
### 默认分级规则
如果未配置自定义告警分级规则,Issue 触发的告警严重程度由系统自动判定:
| 条件 | 严重程度 |
| ---------------- | -------- |
| Issue 存在时间超过 7 天 | Info |
| 崩溃问题 | Critical |
通过累积分数确定等级:
| 分数范围 | 严重程度 |
| ------ | ------------ |
| ≥70 分 | Critical(严重) |
| ≥40 分 | Warning(警告) |
| \<40 分 | Info(提示) |
| 因素 | 评分规则 |
| ---------- | ------------------------------------ |
| **环境影响** | 生产环境(50分)、预发环境(30分)、其他环境(10分) |
| **错误关键词** | 包含严重关键词(+30分)或警告关键词(+15分) |
| **可疑原因** | API 失败(+20分)、代码异常(+15分)、未知/网络错误(+5分) |
| **问题持续时间** | 超过 24 小时(+20分)、超过 12 小时(+10分) |
### 自定义告警分级
您可以在「告警设置」中配置自定义告警分级规则,根据错误的属性特征设定告警优先级(P0 / P1 / P2),实现更精细的告警控制。
自定义分级规则在 Error 上报时评估,得到「预置优先级」。当 Error 聚合到 Issue 时:
* **新建 Issue**:Issue 的优先级由首个 Error 的预置优先级决定
* **匹配已有 Issue**:如果 Error 的预置优先级更高,Issue 优先级自动升级(只升不降)
* **未匹配任何规则**:使用默认优先级 P2
每条分级规则包含以下要素:
| 要素 | 说明 |
| -------- | --------------------------------------------- |
| **规则名称** | 便于识别和管理的名称 |
| **匹配条件** | 基于 Error 属性的筛选条件,同一规则内多个条件为 AND 关系 |
| **告警级别** | 匹配后设定的优先级:P0(Critical)/ P1(Warning)/ P2(Info) |
规则按优先级顺序从上到下逐条评估,**首个匹配的规则立即生效**,后续规则不再检查。您可以通过拖拽调整规则顺序来改变优先级。
每个应用最多可配置 **6 条**告警分级规则。每条规则最多支持 **2 组** OR 条件组,每组最多 **3 个** AND 条件,每个条件最多可填写 **8 个**匹配值。
#### 支持的匹配字段
| 字段 | 说明 | 示例 |
| ------------------------------ | ----------- | ------------------------- |
| 用户 ID(`error.usr_id`) | 上报错误的用户标识 | `vip_001` |
| 用户邮箱(`error.usr_email`) | 用户邮箱地址 | `*@vip.com` |
| 页面 URL(`error.view_url`) | 错误发生的页面完整地址 | 包含 `/payment` |
| 错误类型(`error.error_type`) | 错误的类型分类 | `TypeError`、`SyntaxError` |
| 错误消息(`error.error_message`) | 错误的描述文本 | 包含 `Cannot read property` |
| 堆栈(`error.error_stack`) | 错误的堆栈信息 | 包含 `at handleClick` |
| 环境(`error.env`) | 错误发生的环境 | `production`、`staging` |
| 服务(`error.service`) | 错误所属的服务 | `payment` |
| 版本(`error.version`) | 应用版本号 | `1.2.0` |
| 浏览器(`error.browser_name`) | 浏览器名称 | `Chrome`、`Safari` |
| 浏览器版本(`error.browser_version`) | 浏览器版本号 | `120.0` |
| 是否崩溃(`error.is_crash`) | 是否为崩溃错误 | `true` |
匹配方式支持「包含」和「不包含」两种操作。
#### 配置示例
为 VIP 用户的错误设置最高优先级,确保第一时间响应:
* 匹配条件:用户 ID 包含 `vip`
* 告警级别:P0(Critical)
支付页面是核心业务流程,相关错误需要优先处理:
* 匹配条件:页面 URL 包含 `/payment`
* 告警级别:P1(Warning)
生产环境的崩溃需要立即响应:
* 匹配条件:环境 包含 `production`,且 是否崩溃 包含 `true`
* 告警级别:P0(Critical)
* Issue 的优先级只升不降,确保重要问题不会被后续低优先级的错误降级 - 如需根据
Issue 的影响范围(如影响用户数、错误数量等)调整优先级,请在 Flashduty
集成的[告警处理
Pipeline](/zh/on-call/integration/alert-integration/alert-pipelines) 中配置
## 数据过滤
数据过滤允许您在 Error 聚合为 Issue **之前**过滤掉不需要关注的噪音数据。被过滤的 Error 不会参与 Issue 聚合,也不会产生告警。
您可以在「告警设置」中添加过滤规则。每条规则可设置多个匹配条件,同一规则内的条件为 AND 关系。支持的匹配字段与[自定义告警分级](#自定义告警分级)一致。
| 场景 | 示例规则 |
| --------- | ----------------------------- |
| 排除第三方脚本错误 | 错误堆栈 包含 `cdn.third-party.com` |
| 排除已知无害错误 | 错误消息 包含 `ResizeObserver loop` |
| 排除调试页面错误 | 页面 URL 包含 `/debug` |
* 被过滤的 Error 不会参与 Issue
聚合和告警,但数据仍然保留,可在查看器中通过筛选条件查看 -
如果只是想暂时屏蔽某类告警但保留 Issue 数据,建议使用 Flashduty 告警处理
Pipeline 中的「告警丢弃」功能
## 与 Flashduty 协同
RUM 告警与 Flashduty 深度协同,形成完整的告警处理链路:
| 层级 | 配置位置 | 核心能力 | 适用场景 |
| ---- | -------------- | ---------------- | ------------------- |
| 数据过滤 | RUM 告警设置 | 过滤噪音 Error | 永久忽略第三方脚本错误、调试页面错误等 |
| 告警分级 | RUM 告警设置 | 根据 Error 属性设定优先级 | VIP 用户告警、核心页面告警等 |
| 告警处理 | Flashduty 集成配置 | 标题定制、优先级调整、丢弃/抑制 | 根据影响用户数调整级别、抑制重复告警等 |
| 告警分派 | Flashduty 协作空间 | 路由、值班排班、通知渠道 | 分派到不同团队、配置通知方式等 |
选择 Flashduty 协作空间投递时,您可以在 Flashduty 的[告警处理 Pipeline](/zh/on-call/integration/alert-integration/alert-pipelines) 中进一步处理 RUM 告警,例如根据影响用户数调整告警级别、按时间窗口抑制重复告警、自定义告警标题格式等。选择 Webhook 投递时,RUM 告警不会进入这条 On-call 处理链路,请在您的接收端完成格式转换、路由和通知。
## 延伸阅读
典型场景配置方案,快速减少无效告警干扰
在集成层对告警进行清洗、转换和过滤
在协作空间层面聚合和抑制告警
配置分派策略,将告警路由到正确的值班人员
# Issue 状态
Source: https://docs.flashduty.com/zh/rum/error-tracking/issue-status
了解 Flashduty RUM Issue 状态流转情况
在异常追踪中,所有 Issue 都有一个状态,帮助您对问题进行分类和优先级排序。
## 状态类型
| 状态 | 标识 | 说明 |
| ------- | ------------ | -------------------- |
| **待处理** | `for_review` | 需要关注的新问题或回归问题 |
| **处理中** | `reviewed` | 已分类且需要修复的问题,可立即或稍后处理 |
| **已忽略** | `ignored` | 不需要进一步调查或处理的问题 |
| **已解决** | `resolved` | 已修复且不再发生的问题 |
所有新发现的 Issue 初始状态为**待处理(for\_review)**。Flashduty 会根据特定条件自动更新状态,您也可以手动调整。
## 自动解决 Issue
Flashduty 会自动将不活跃或已解决的 Issue 标记为**已解决(resolved)**:
如果 Issue 最后一次报告的版本已超过 14 天,且新版本中未再次出现该错误,系统会自动将其解决。
如果未设置 `version` 标签,当 Issue 在过去 14 天内没有新错误报告时,系统会自动将其解决。
正确配置应用程序的 `version` 标签对于准确识别已解决的 Issue 至关重要。
## 自动重新打开 Issue
Flashduty 具备 Issue 检测功能,当已解决的 Issue 再次出现时,系统会自动重新打开并标记为\*\*待处理(for\_review)\*\*状态,同时在活动时间线中记录该事件为「问题复现」状态。
### 什么是问题复现?
复现指的是先前已修复的问题在代码更新后意外重新出现。Flashduty 的回归检测可自动识别这些情况,将相关 Issue 重新打开,而不是创建重复的 Issue,从而保留问题的完整上下文和历史记录。
### 复现检测机制
当满足以下任一条件时,复现检测将被触发:
* 如果\*\*已解决(resolved)\*\*的错误在代码的更新版本中重新出现
* 如果在未设置版本标签的情况下,\*\*已解决(resolved)\*\*状态的错误再次出现
一旦检测到问题复现,Flashduty 会:
自动将 Issue 状态变更为**待处理(for\_review)**
为 Issue 添加**问题复现**标签,便于快速识别
### 关联版本配置
复现检测会考虑错误发生的服务版本信息,只有在 Issue 标记为\*\*已解决(resolved)\*\*后的新版本中才会触发检测。
```javascript theme={null}
window.FLASHCAT_RUM.init({
applicationId: "rum-application-id",
environment: "production",
version: "1.0.0", // 确保设置正确的版本号
});
```
如果不设置版本标签,当已解决的 Issue 再次发生错误时,系统仍会将其标记为「问题复现」,但无法确定是否在新版本中发生。
## 手动更新状态
您可以在任何显示 Issue 的地方手动更新其状态,包括 Issue 列表或详情面板。
只需点击当前状态,然后从下拉菜单中选择新状态即可。
## 最佳实践
定期检查\*\*待处理(for\_review)\*\*状态的 Issue,确保新问题和回归问题得到及时处理
始终为应用程序配置正确的版本标签,以便系统能准确识别已解决的问题
通过有效管理 Issue 状态,您的团队可以更专注于解决重要问题,减少处理噪声的时间,提升整体开发效率。
## 下一步
了解如何查看和分析异常详情
# 异常追踪
Source: https://docs.flashduty.com/zh/rum/error-tracking/overview
掌握 Flashduty RUM 的异常追踪功能,快速发现并解决网站问题。
Flashduty RUM(Real User Monitoring)是一款强大的用户体验监控工具,专注于帮助开发者快速发现并解决网站和应用中的问题,确保系统稳定性和用户体验的流畅性。它通过自动捕获各类异常信息,并提供详细的上下文数据,让您能够精准定位问题根源,及时采取措施进行修复。
## 核心功能
自动捕获 JavaScript 异常、网络请求失败、资源加载异常等各类问题,并提供详细的错误堆栈信息和上下文数据
支持自动错误捕获和手动错误上报两种方式,允许您记录业务逻辑中的已处理错误,并附加上下文信息
将相似的异常事件归类为同一个 Issue,减少重复告警,帮助开发团队更高效地识别和处理问题
通过上传 SourceMap 文件,将压缩后的代码映射到原始源代码,直接定位到原始代码的具体位置
## 价值与优势
| 优势 | 描述 |
| ------------ | ---------------------------------- |
| **提高问题解决效率** | 快速定位问题根源,减少故障排查时间,提高开发和运维团队的工作效率 |
| **优化用户体验** | 及时发现并解决影响用户体验的问题,提升用户满意度和忠诚度 |
| **降低业务风险** | 避免因系统故障导致的业务损失,保障业务的稳定运行 |
| **提供数据支持** | 详细的异常数据和上下文信息为业务决策提供有力支持,帮助您不断优化产品 |
## 使用场景
在开发过程中,快速定位和解决 JavaScript 代码中的错误,提高开发效率。
实时监控生产环境中的异常情况,及时发现并处理潜在问题,保障系统的稳定性。
了解用户在使用过程中遇到的问题,针对性地改进产品,提升用户体验。
## 异常追踪流程
Flashduty RUM 的异常追踪分为两个关键阶段:**问题发现** 和 **问题定位**。
快速发现异常问题的触发点是诊断的第一步。Flashduty RUM 提供以下方式帮助您识别问题:
* **数据分析**:通过**分析看板**的「异常」Tab,查看错误率、异常类型等数据趋势
* **告警通知**:通过在应用中开启告警,与**协作空间**联动,可在异常发生时及时感知
* **主动巡检**:在**异常追踪**模块观察异常趋势,如 JavaScript 错误、网络错误等
Flashduty RUM 提供丰富的异常数据和上下文信息,帮助您精准定位问题根因。
### 核心异常数据
| 异常类型 | 说明 |
| ------------- | ------------------ |
| JavaScript 错误 | 运行时错误、语法错误等 |
| 网络请求错误 | API 调用失败、超时等 |
| 资源加载错误 | 图片、脚本等资源加载失败 |
| 框架相关错误 | React、Vue 等框架的组件错误 |
### 上下文信息
* **用户环境**:浏览器类型、设备型号、操作系统
* **错误堆栈**:详细的调用栈信息
* **会话时间线**:触发错误的操作路径
### 问题分类与定位
| 问题类型 | 典型表现 | 可能原因 | 关键指标 |
| ----------------- | ---------- | --------------- | ---------- |
| **JavaScript 错误** | 功能失效、控制台报错 | 代码逻辑错误、浏览器兼容性问题 | 错误率、错误类型 |
| **网络请求错误** | 请求超时、连接中断 | API 响应慢、网络质量差 | 请求延迟、连接成功率 |
| **资源加载错误** | 图片/脚本加载失败 | CDN 配置错误、资源路径错误 | 资源加载失败率 |
| **框架相关错误** | 组件渲染失败 | 组件逻辑错误、状态管理问题 | 组件错误率 |
## 问题定位工具
通过错误分析面板,您可以查看聚合后的 Issue 列表、错误趋势和详细信息。
上传 SourceMap 后,可以直接在堆栈信息中查看原始源代码位置。
问题解决后,可在系统中流转 Issue 状态,并持续关注异常数据的变化趋势。
## 下一步
了解异常上报规则和方式
查看和分析异常详情
配置源码映射提升调试效率
了解异常聚合机制
# 源码映射与异常追踪
Source: https://docs.flashduty.com/zh/rum/error-tracking/source-mapping
本文档详细介绍如何使用 RUM 进行源码映射管理,以及如何通过源码映射进行异常追踪和调试。
Flashduty 支持多平台的符号文件上传与源码映射,帮助开发者将混淆或压缩后的错误堆栈还原为可读的原始源代码。
* **Web(JavaScript)**:通过 [Flashduty CLI](https://github.com/flashcatcloud/flashcat-cli) 上传 `sourcemap` 文件
* **微信小程序**:通过 Flashduty CLI 上传 `miniprogram-ci get-dev-source-map` 生成的 `sourcemap.zip`
* **HarmonyOS**:通过 `@flashcatcloud/hvigor-plugin` 上传 ArkTS `sourceMaps.map`、可选 `nameCache.json` 和 Native `.so` 符号文件
* **Android**:通过 Gradle 插件自动上传 ProGuard/R8 mapping 文件和 NDK 符号文件
* **iOS**:通过 Flashduty CLI 上传 dSYM 符号文件
* **Flutter**:通过 Flashduty CLI 上传 `--split-debug-info` 生成的 Dart AOT 符号文件(`.symbols`),还原 Android 上混淆后的 Dart 异常堆栈;iOS 原生崩溃与原生 iOS 应用一样走 dSYM
* **Electron**:通过 Flashduty CLI 上传 Breakpad `.sym` 符号文件,按模块 Debug ID 匹配原生崩溃堆栈;详见 [Electron 错误还原](/zh/rum/sdk/electron/error-symbolication)
用户可在「应用管理」-「源码管理」菜单查看已上传的符号文件,并通过上传面板生成脚本在本地执行上传操作。
## 为什么需要源码映射?
在现代应用开发中,代码通常会被压缩、混淆或编译,以优化加载速度和性能。无论是 Web 端的 JavaScript 压缩、微信小程序的发布包转换、HarmonyOS 的 ArkTS 构建产物、Android 的 ProGuard/R8 混淆,还是 iOS 的编译优化,这些处理都会导致错误堆栈中的代码位置信息无法直接映射到原始源代码,增加了调试难度。
`SourceMap` 记录了压缩代码与原始代码之间的映射关系,允许开发者在调试时查看未压缩的源代码
通过 `SourceMap` 可以在异常追踪中直接定位到原始源代码中的具体位置
开发者无需手动解码压缩文件,节省排查问题的时间
## 生成 SourceMap
大多数现代构建工具(如 Webpack、Rollup 或 Vite)都支持生成 `SourceMap`。
在 `webpack.config.js` 中启用 `SourceMap` 生成:
```javascript theme={null}
module.exports = {
mode: "production",
devtool: "source-map", // 生成独立的 .map 文件
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
},
};
```
构建后,`dist` 目录中会生成 `bundle.js` 和对应的 `bundle.js.map` 文件。
在 `vite.config.js` 中配置:
```javascript theme={null}
export default {
build: {
sourcemap: true, // 生成 sourcemap
},
};
```
在 `rollup.config.js` 中配置:
```javascript theme={null}
export default {
output: {
sourcemap: true,
},
};
```
## 上传 SourceMap
使用 Flashduty CLI 将 `sourcemap` 文件上传至 Flashduty 服务器。
确保已安装 Node.js,然后通过 npm 安装:
```bash theme={null}
npm install -g @flashcatcloud/flashcat-cli
```
在「应用管理」-「源码管理」菜单中,点击「上传源码」面板,填写以下信息:
用于认证您的身份
应用的服务名(例如 `my-service`)
应用的发布版本(例如 `1.0.0`)
压缩文件的路径前缀(例如 `/assets`)
仅私有化部署需要填写。私有化部署时面板会自动填入部署下发的上报地址,可手动覆盖(协议 + 域名,不带路径,例如 `https://rum.example.com`);留空则默认上传到 Flashcat SaaS。
在项目根目录下运行生成的脚本:
```bash theme={null}
flashcat-cli sourcemaps upload \
--service my-service \
--release-version 1.0.0 \
--minified-path-prefix /assets \
--api-key your-api-key \
./dist
```
私有化部署时,在命令前加上 `FLASHCAT_SOURCEMAP_INTAKE_URL` 环境变量即可将符号文件上传至自定义入口,例如 `FLASHCAT_SOURCEMAP_INTAKE_URL=https://rum.example.com flashcat-cli sourcemaps upload ...`(协议 + 域名,不带路径);未设置时默认上传到 Flashcat SaaS。填写「自定义上传 Endpoint」后,面板生成的命令会自动带上该变量。
* 确保 `minified-path-prefix` 与实际部署的压缩文件路径一致
* 上传成功后,可在「应用管理」-「源码管理」中查看已上传的 `sourcemap` 文件
## 上传微信小程序 SourceMap
微信小程序发布后,线上错误堆栈通常只包含转换后的文件路径和行列号。你可以先使用 `miniprogram-ci get-dev-source-map` 生成 `sourcemap.zip`,再通过 Flashduty CLI 上传。上传后,Flashduty 会按服务名、版本和文件路径匹配小程序错误堆栈,并在异常详情中展示还原后的源码位置。
在小程序项目中运行 `miniprogram-ci get-dev-source-map`,生成可上传的 `sourcemap.zip` 文件。该文件路径会作为上传命令的 `--sourcemap-zip` 参数。
`miniprogram-ci get-dev-source-map` 默认输出的 zip 结构即满足以下要求,通常无需手动调整:
* 主包的 `.js.map` 条目放在 `__FULL__/` 目录下,例如 `__FULL__/app-service.js.map`
* 分包的 `.js.map` 条目放在以分包名命名的目录下,例如 `subpkg-a/chunk_0.appservice.js.map`,目录名会作为分包标识写入元数据
* 只有 `.js.map` 后缀的条目会被采纳,其他文件(README、source 文件等)会被忽略
* 若 zip 中找不到任何 `.js.map` 条目,上传会返回错误 `No .js.map entries found in the sourcemap archive`
单个 `.js.map` 解压后不超过 50 MB;整个 zip 解压后聚合不超过 500 MB;zip 内总条目数不超过 5000。超出限制时上传会返回 HTTP 413。
在「应用管理」-「源码管理」菜单切换到「微信小程序」标签页,点击「上传源码」。上传面板会根据表单内容生成命令。
用于认证上传请求。页面会优先展示当前账户可访问的 API Key。
小程序应用的服务名,例如 `my-mp`。异常解析时会使用该值与错误事件中的 `service` 匹配。
小程序发布版本,例如 `1.2.3`。异常解析时会使用该值与错误事件中的版本匹配。
`miniprogram-ci get-dev-source-map` 输出的压缩包路径,例如 `./sourcemap.zip`。
微信小程序 appid,例如 `wxbad3e0a65782821c`。多小程序场景下用于区分不同小程序的同名 service + version 上传记录;只有一个小程序时可省略。
在项目根目录下运行生成的命令;`--appid` 为可选参数,未填写时上传命令中不会出现这一行:
```bash theme={null}
FLASHCAT_API_KEY=your-api-key flashcat-cli sourcemaps upload-miniprogram \
--service my-mp \
--release-version 1.2.3 \
--sourcemap-zip ./sourcemap.zip \
--appid wxbad3e0a65782821c
```
## 上传 HarmonyOS 符号文件
HarmonyOS 崩溃栈可能同时包含 **ArkTS / JS 帧** 和 **Native `.so` 帧**。要在控制台中同时还原这两类堆栈,请上传以下构建产物:
* `sourceMaps.map`:ArkTS sourcemap 主文件
* `nameCache.json`:可选,用于还原混淆后的标识符名称
* 未 strip 的 Native `.so`:用于符号化 C/C++ 崩溃栈
控制台的 **应用管理 → 源码管理 → HarmonyOS** 上传面板会要求你填写 **Service**、**Version** 和 **API Key**,并生成对应的 `hvigor` 配置和上传命令。`service` 与 `version` 必须和应用实际上报的值保持一致,否则服务端无法匹配到对应符号文件。
在 HarmonyOS 工程中安装上传插件:
```bash theme={null}
npm install -D @flashcatcloud/hvigor-plugin@^0.1.3
```
把控制台面板生成的 `service`、`version` 与 `apiKey` 配置写入 `hvigorfile.ts`:
```ts hvigorfile.ts theme={null}
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
import { flashcatSymbolUploadPlugin } from '@flashcatcloud/hvigor-plugin';
export default {
system: hapTasks,
plugins: [
flashcatSymbolUploadPlugin({
apiKey: process.env.FLASHCAT_API_KEY ?? '',
service: 'my-app',
version: '1.0.0',
enabled: process.env.FLASHCAT_UPLOAD === '1'
})
]
};
```
在构建产物生成后执行上传任务:
```bash theme={null}
FLASHCAT_UPLOAD=1 FLASHCAT_API_KEY=your-api-key \
hvigorw uploadFlashcatSymbols --mode module -p module=entry@default -p product=default
```
* 公有云省略 `endpoint` 时,**hvigor-plugin ≥ 0.1.3** 默认上传到 `https://ci.flashcat.cloud`。不要用 RUM 上报域名 `browser.flashcat.cloud`(会 404)。私有化设置 `FLASHCAT_SOURCEMAP_INTAKE_URL`(需 ≥ 0.1.3)或显式传 `endpoint`
* Native `.so` 需要保留 GNU build-id;HarmonyOS NDK 默认开启,如你的构建链路关闭了它,请显式添加 `-Wl,--build-id`
* 更完整的 HarmonyOS 接入、符号上传和兼容性说明,请继续阅读 [HarmonyOS SDK 高级配置](/zh/rum/sdk/harmony/advanced-config)
## 上传 Android 符号文件
Android 应用使用 ProGuard/R8 进行代码混淆后,错误堆栈中的类名和方法名会被替换为无意义的短名称。通过上传 mapping 文件,Flashduty 可以将混淆后的堆栈还原为原始代码。
对于包含 NDK 原生代码的应用,还需要上传 NDK 符号文件以还原 C/C++ 层的堆栈。
在应用模块的 `build.gradle` 中添加 Flashcat Android Gradle 插件:
```groovy theme={null}
plugins {
id("cloud.flashcat.android-gradle-plugin") version "1.2.0"
}
```
Kotlin DSL 使用相同的插件 ID:
```kotlin theme={null}
plugins {
id("cloud.flashcat.android-gradle-plugin") version "1.2.0"
}
```
通过 Gradle 属性、环境变量或项目配置文件提供 API Key。发布流水线中通常使用环境变量:
```bash theme={null}
# 二选一
export FC_API_KEY=your-api-key
export FLASHCAT_API_KEY=your-api-key
# 可选:私有化部署时指定自定义上传入口
export FLASHCAT_SOURCEMAP_INTAKE_URL=https://rum.example.com
```
也可以在项目根目录创建 `flashcat-ci.json`:
```json theme={null}
{
"apiKey": "your-api-key",
"flashcatSite": "ci.flashcat.cloud",
"sourcemapEndpoint": "https://rum.example.com"
}
```
API Key 可在控制台的「API Key 管理」页面创建和管理。
在应用模块的 `build.gradle` 中添加 `flashcat` 配置块。未显式配置时,插件会从 Android 构建配置读取 `versionName`、`versionCode` 和应用包名。
```groovy theme={null}
flashcat {
versionName = "1.3.0" // 可选,默认读取 Android 配置中的 versionName
serviceName = "my-service" // 可选,默认使用应用包名
site = "CN" // 可选,可选值:CN、STAGING,默认 CN
sourcemapEndpoint = "https://rum.example.com" // 可选,私有化自定义上传入口;未带 /sourcemap/upload 时会自动补全
checkProjectDependencies = "none" // 可选:none、warn、fail;默认不检查
mappingFilePath = "path/to/mapping.txt" // 可选,自定义 mapping 文件路径
nonDefaultObfuscation = false // 可选,使用 DexGuard 等非默认混淆工具时设为 true
ignoreFlashcatCiFileConfig = false // 可选,是否忽略 flashcat-ci.json
additionalSymbolFilesLocations = ["/path/to/location/obj"] // 可选,额外 NDK 符号目录
}
```
默认情况下插件会根据 `site` 选择上传入口:`CN` 对应 `ci.flashcat.cloud`,`STAGING` 对应 `ci-dev.flashcat.cloud`。私有化部署可通过 `sourcemapEndpoint` 指定自定义上传入口(自 `1.2.0` 起支持);该值未带 `/sourcemap/upload` 路径时会自动补全。三种配置方式的优先级为:`flashcat {}` 扩展配置 > `flashcat-ci.json` > `FLASHCAT_SOURCEMAP_INTAKE_URL` 环境变量。配置自定义入口后,`site` 仅用于回退,不再影响实际上传地址。
在构建完成后,执行 Gradle 任务上传符号文件:
```bash theme={null}
# 上传 ProGuard/R8 mapping 文件
./gradlew uploadMappingRelease
# 如果项目包含 NDK 原生代码,上传 NDK 符号文件
./gradlew uploadNdkSymbolFilesRelease
```
插件会为启用混淆的 variant 创建 `uploadMapping` 任务。NDK 符号上传任务会在项目存在 native build,或配置了 `additionalSymbolFilesLocations` 时创建。若项目使用多个 flavor,请为每个发布 variant 分别执行对应任务。
**NDK 符号文件必须是未剥离(unstripped)的 ELF 文件,且包含 GNU build-id 节。**
上传服务器会读取每个 `.so` 文件的 `.note.gnu.build-id` ELF 节以提取 build-id,并以此作为符号化寻址的唯一键。若文件缺少该节,上传立即返回 HTTP 400,错误信息为:
```
libfoo.so: .note.gnu.build-id section not found. Build the .so with -Wl,--build-id and upload the unstripped file
```
**常见原因及修复:**
* **CMake Release 构建默认剥离符号**:CMake 在 `CMAKE_BUILD_TYPE=Release` 时会在链接后执行 `strip`,移除 `.note.gnu.build-id` 节。需在 `CMakeLists.txt` 中显式添加链接标志:
```cmake theme={null}
target_link_options(mylib PRIVATE -Wl,--build-id)
```
或对整个项目生效:
```cmake theme={null}
add_link_options(-Wl,--build-id)
```
* **手动 strip 脚本**:如果 CI 流水线在上传前对 `.so` 运行了 `strip` 命令,需确保上传的是 `obj/` 目录下的原始未剥离文件,而不是 `libs/` 目录下已剥离的发布产物。`additionalSymbolFilesLocations` 参数用于指定此路径。
NDK 原生符号文件在 API 中以 `event.type=ndk_symbol_file` 标识,区别于 ProGuard mapping 文件的 `event.type=jvm_mapping_file`。自定义上传集成(不使用 Gradle 插件)时需传入正确的类型字段。
## 上传 iOS dSYM 文件
iOS 应用在编译时会生成 dSYM(Debug Symbol)文件,其中包含将内存地址映射回源代码位置所需的调试符号信息。上传 dSYM 文件后,Flashduty 可以将崩溃堆栈中的地址还原为可读的函数名、文件名和行号。
确保已安装 Node.js,然后通过 npm 安装:
```bash theme={null}
npm install -g @flashcatcloud/flashcat-cli
```
dSYM 文件可从以下位置获取:
* **Xcode 本地构建**:在 Xcode 的 Build Products 目录中找到 `.dSYM` 文件
* **Xcode Archive**:通过 Organizer 窗口导出 dSYMs
* **App Store Connect**:从 App Store Connect 下载 dSYMs(需要在构建设置中启用符号上传)
使用 Flashduty CLI 上传 dSYM 文件:
```bash theme={null}
FLASHCAT_API_KEY=your-api-key flashcat-cli dsyms upload ./app.dSYM
# 可选:私有化部署时指定自定义上传入口(协议 + 域名,不带路径);未设置时默认上传到 Flashcat SaaS
FLASHCAT_API_KEY=your-api-key FLASHCAT_SOURCEMAP_INTAKE_URL=https://rum.example.com flashcat-cli dsyms upload ./app.dSYM
```
您也可以在控制台的「源码管理」面板中,填写参数后自动生成上传命令。
## 上传 Flutter 符号文件
Flutter 应用使用 `--obfuscate` 混淆构建后,Dart 异常堆栈中的符号会被剥离,只剩地址信息。通过上传 `--split-debug-info` 生成的 Dart AOT 符号文件(`app.-.symbols`),Flashduty 会读取符号文件的 ELF GNU build-id,与堆栈中携带的 build ID 匹配,还原 Android 上的 Dart 异常堆栈。Flutter 符号文件在上传 API 中以 `event.type=flutter_symbol_file` 标识。
Android 构建时开启混淆并指定符号输出目录:
```bash theme={null}
flutter build apk --obfuscate --split-debug-info=./debug-symbols
```
在「应用管理」-「源码管理」菜单切换到「Flutter」标签页,点击「上传源码」。上传面板会根据表单内容生成命令。
用于认证上传请求,对应命令中的 `FLASHCAT_API_KEY` 环境变量。
`--split-debug-info` 指定的符号目录,例如 `./debug-symbols`。
应用的服务名,例如 `my-app`。建议与 SDK 初始化时设置的 `service` 保持一致,便于在控制台按服务归类筛选。
应用的发布版本,例如 `1.0.0`。建议与 SDK 初始化时设置的 `releaseVersion` 保持一致。
在项目根目录下运行生成的命令:
```bash theme={null}
FLASHCAT_API_KEY=your-api-key flashcat-cli flutter-symbols upload ./debug-symbols \
--service my-app \
--release-version 1.0.0
```
**iOS 的 Dart 堆栈暂不支持符号化。** Flutter 为 Apple 平台生成的符号文件是 Mach-O 格式,平台当前只能解析 Android 侧的 ELF 格式,因此 iOS 的 `.symbols` 上传会被拒绝。iOS 原生崩溃(Objective-C / Swift / C / C++)不受影响,与原生 iOS 应用一样上传 dSYM 即可符号化。
如果你的应用同时发布 iOS 和 Android,`--obfuscate` 仍可开启:Android 的 Dart 堆栈会正常还原,iOS 的 Dart 堆栈则保持混淆状态。若 iOS 的可读堆栈更重要,则该端构建时不要开启 `--obfuscate`。
符号文件与崩溃事件通过 build ID 匹配,`service` 与 `release-version` 不参与解析,仅影响控制台列表的归类与筛选。符号文件支持 `arm`、`arm64`、`x64` 架构,由 `.symbols` 文件名自动识别。每次改动 Dart 代码都会生成新的 build ID,因此符号上传必须纳入每一次发布构建。更完整的 Flutter 符号化说明请参阅 [Flutter SDK 高级配置](/zh/rum/sdk/flutter/advanced-config)。
## 符号文件管理
在 Flashduty 平台上,符号文件的管理通过「应用管理」-「源码管理」菜单完成:
| 功能 | 说明 |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 查看已上传的符号文件 | 列出所有已上传的文件(SourceMap、小程序 SourceMap、ProGuard mapping 文件、dSYM、NDK 原生符号文件、Flutter 符号文件),包括路径、服务名、版本号、大小和上传时间。Android 标签页同时展示 ProGuard mapping 文件和 NDK 原生符号文件,NDK 行会显示 build\_id、arch 和 lib\_name 列 |
| 按平台筛选 | 在 Web、iOS、Android、微信小程序、HarmonyOS、Flutter 和 Electron 标签页之间切换,查看不同平台的符号文件 |
| 版本管理 | 通过 `service` 和 `release-version` 参数为不同版本的应用分别管理 |
| 小程序维度 | 微信小程序列表会展示符号文件元数据中的 AppID(取自 `metadata.appid`)和分包(取自 `metadata.subpackage`)两列;主包没有分包标识时显示「主包」,AppID 未上传时显示 `-` |
| 权限控制 | 通过 `API Key` 确保只有授权用户可以上传或管理 |
## 在异常追踪中查看源码
RUM 异常追踪支持结合 Web `sourcemap`、微信小程序 SourceMap、Android mapping 文件和 iOS dSYM 还原错误堆栈,在异常详情中查看原始源码位置,精确定位问题。
RUM SDK 会自动捕获应用错误,并将错误堆栈信息发送至服务器。Web 场景通常包括 JavaScript 异常、Promise 拒绝和网络错误;Native 场景则包括崩溃、异常和符号化所需的堆栈信息。
```javascript theme={null}
throw new Error("Something went wrong");
```
当错误堆栈中的文件路径、行号或地址信息与已上传的 Web `sourcemap`、微信小程序 SourceMap、Android ProGuard mapping 文件、Android NDK 原生符号文件或 iOS dSYM 文件匹配时,Flashduty 会自动将压缩、混淆或编译后的错误位置映射到原始源代码。
**压缩文件堆栈:**
```
Error: Something went wrong
at Object. (/assets/index-5e0391ac.js:1:123)
```
**映射后的源代码:**
```
Error: Something went wrong
at App.render (src/components/App.js:45:10)
```
在异常追踪模块中,点击具体的错误记录,可以查看:
* **错误消息**:如 `Something went wrong`
* **原始堆栈**:映射后的源代码文件路径、行号和列号
* **上下文代码**:显示错误位置附近的源代码片段
如果小程序错误堆栈尚未解析,异常详情中的提示会跳转到「源码管理」的小程序类型,并可直接打开上传面板补充对应版本的 `sourcemap.zip`。
根据映射后的源代码位置,直接在本地开发环境中找到对应代码,分析问题根因并修复。
## 最佳实践
在 CI/CD 流水线中集成上传命令,确保每次发布时自动上传 Web `sourcemap` 或微信小程序 `sourcemap.zip`。
**GitHub Actions 示例:**
```yaml theme={null}
- name: Upload SourceMaps
run: |
flashcat-cli sourcemaps upload \
--service my-service \
--release-version ${{ github.sha }} \
--minified-path-prefix /assets \
--api-key ${{ secrets.FLASHCAT_API_KEY }} \
./dist
```
使用 `--release-version` 参数与应用版本号保持一致,便于追踪特定版本的 `sourcemap`。
在资源上传 CDN 之前删除 `sourcemap` 文件,避免将源码信息带入生产环境。
上传 `sourcemap` 后,主动抛出测试错误,验证异常追踪模块是否能正确映射到源代码。
## 常见问题
* 确认 `sourcemap` 是否成功上传,且 `minified-path-prefix` 与实际部署路径一致
* 检查 `service` 和 `release-version` 是否与错误发生时的应用版本匹配
* 如果是微信小程序,确认已上传对应版本的 `sourcemap.zip`
* 确保 `sourcemap` 文件仅上传至 Flashduty 服务器,不直接暴露在公网
* 在生产环境中,移除对 `sourcemap` 文件的直接访问(如通过 Nginx 配置)
* 检查 `API Key` 是否有效
* 确保网络连接正常,CLI 版本是最新的
可以。对于早期版本 SDK 把堆栈塞进 message 字段的小程序错误,Flashduty 会自动从 message 中识别堆栈并参与 SourceMap 还原与异常分组。升级到新版 SDK 后,已存在的历史错误也会按这一规则重新归类,可能与升级前的分组不完全一致。
## 下一步
了解异常聚合机制
管理 Issue 状态流转
# 数据查询语法指南
Source: https://docs.flashduty.com/zh/rum/explorer/data-query
掌握 Flashduty RUM 查看器的搜索语法,通过灵活的查询条件快速定位和分析用户数据。
Flashduty RUM 查看器提供了强大的检索能力,允许您通过灵活的查询语法快速定位和分析 RUM 数据。查询由**词项**(terms)和**操作符**(operators)组成,支持复杂的搜索条件组合。
## AI 自然语言查询
如果您还不熟悉查询语法,可以直接用自然语言描述想要查找的数据,AI 会自动将其转换为查询语句。
点击查询输入框中的**魔法棒**图标进入 AI 自然语言查询模式。进入后输入框边框会高亮,与普通查询模式明确区分。
用自然语言描述您想查找的数据(支持中英文),然后按**回车**转换。例如:
```
来自 Chrome 浏览器、耗时超过 2 秒的 5xx 资源请求
```
AI 会将其转换为:
```
browser_name:Chrome resource_status_code:>=500 resource_duration:>2s
```
AI 生成对应的查询语句并展示预览。确认无误后点击**应用**,查询立即生效;若结果不理想,可继续修改描述后再次回车重新生成,或点击**撤销**回退到应用前的状态。
AI 生成的是标准查询语句(DQL),使用的字段与语法与手动查询完全一致(详见下文)。您无需记住字段名称,AI 会根据当前事件类型自动选择可查询的字段。
### 追加而非替换
当输入框中已有查询条件时,AI 生成的条件会**追加**到现有查询之后,而不会覆盖它。因此您可以在已有查询的基础上,用自然语言逐步补充筛选条件。若当前为空查询,则直接应用生成结果。
如果您的描述更适合其他事件类型,AI 会提示切换(如「将切换事件类型为 错误」),并在该事件类型的可查询字段范围内生成查询。
在 AI 输入框中用**自然语言**描述意图即可,无需手写查询语句(如 `browser_name:Chrome`)——直接输入查询语法反而会降低转换准确率。需要精确控制查询条件时,请改用下方的查询语法。
## 查询基础
查询支持两种类型的词项:
| 类型 | 说明 | 示例 |
| ------- | ---------- | ------------------- |
| **单词项** | 单个词汇 | `test`、`hello` |
| **短语** | 用双引号包围的词汇组 | `"hello flashduty"` |
### 布尔操作符
| 操作符 | 描述 | 示例 |
| ----- | ------------------------------- | -------------------- |
| `AND` | 交集:两个词项都必须在选定的视图中(默认操作符) | `error AND timeout` |
| `OR` | 并集:任一词项包含在选定的视图中,需要使用 `()` 包裹起来 | `(error OR warning)` |
| `-` | 排除:后面的词项不在视图中 | `error -timeout` |
## AI 自然语言查询
如果你不想手写 DQL,可以让 AI 将自然语言请求转换为查询条件。在 RUM 查看器的查询框左侧点击 **AI 自然语言查询** 图标;也可以在普通查询模式下按 ⌘ + Enter (Windows 和 Linux 为 Ctrl + Enter )。
用自然语言描述你想查看的数据,例如“Chrome 浏览器上的报错”“耗时超过 2 秒的资源请求”或“过去 24 小时的 checkout 页面”。按 Enter 生成预览。
预览会显示将要加入的 DQL 条件;当请求更适合其他事件类型或时间范围时,也会显示事件类型或时间范围的变更。
点击 **应用**、**追加到查询** 或 **切换并应用** 确认变更。应用后,提示消息中会提供 **撤销**,用于恢复应用前的查询、事件类型和时间范围。
“最近 1 小时”“昨天”“过去 7 天”等时间表达会更新查看器的时间选择器,不会被写成 `client_time` 等 DQL 条件。性能时长条件仍然属于 DQL,例如 `view_loading_time:>2s`。
AI 自然语言查询的时间范围最长为 **14 天**。如果请求的范围更长,预览会提示已截取最近 14 天;应用后时间选择器会使用截取后的范围。相对时间范围会改为过去 14 天,绝对时间范围会保留请求的结束时间,并向前取 14 天。
## 全文检索
全文检索仅部分字段支持,如未查询到结果,请转为字段查询。
| 查询语句 | 描述 |
| --------------- | ------------------------ |
| `hello` | 精确匹配 `hello` 的字段 |
| `hello*` | 匹配以 `hello` 开头的字段 |
| `*hello` | 匹配以 `hello` 结尾的字段 |
| `*hello*` | 匹配含有 `hello` 的字段 |
| `"hello world"` | 精确匹配 `"hello world"` 的字段 |
## 转义特殊字符
检索包含特殊字符的字段值时,需要使用反斜杠 `\` 转义或者双引号。
以下字符被视为特殊字符:`:`, `"`, `*`, `-`, `>`, `<`, `,`, `(`, `)`, `[`, `]`, `\` 和空格
## 属性检索
使用 `attribute:term` 语法检索特定属性:
| 查询语句 | 描述 |
| ------------------------- | ----------------------- |
| `browser_name:Chrome` | 检索值为 `Chrome` 的浏览器 |
| `view_name:*/detail` | 检索以 `/detail` 结尾的视图名称 |
| `-resource_status_code:0` | 检索状态码不为 `0` 的资源 |
| `os_name:"Mac OS X"` | 检索值为 `"Mac OS X"` 的系统名称 |
## 数值检索
对于数值类型的属性,可以使用比较操作符:
| 查询语句 | 描述 |
| ----------------------------- | ------------------------ |
| `session_error_count:>5` | 检索错误数大于 `5` 的会话 |
| `view_time_spent:>=1.00min` | 检索停留时间大于 `1min` 的视图 |
| `session_view_count:[2 TO 8]` | 检索视图访问量在 `2` 和 `8` 之间的会话 |
## 复杂检索示例
检索钱包页面中发生的 Warning 类型的错误:
```
error_message:Warning\:* view_url_path:/wallet/*
```
检索加载时间超过 5 秒,且以 `/incident/detail/` 开头的视图:
```
view_loading_time:>=5s view_url_path:/incident/detail/*
```
检索请求类型为 `fetch` 或者 `xhr`,且状态码不为 `200` 的资源:
```
-resource_status_code:200 resource_type:(fetch OR xhr)
```
检索 URL 为 `/incident`,且操作数大于 `2` 或者错误数大于 `3` 的视图:
```
view_url_path:/incident (view_action_count:>=2 OR view_error_count:>=3)
```
## 微信小程序专属属性
针对微信小程序平台采集的 View 事件,除通用的 `view_*` 字段外,还支持以下可查询属性,便于排查小程序页面冷启动、`setData` 调用和生命周期阶段耗时:
| 属性 | 说明 |
| ------------------------ | -------------------------- |
| `view_first_render` | 首屏渲染耗时 |
| `view_app_launch` | 小程序启动耗时 |
| `view_loading_time` | 页面加载耗时 |
| `view_setdata_count` | 页面 `setData` 调用次数 |
| `view_setdata_duration` | 页面 `setData` 累计耗时 |
| `view_onload_to_onshow` | `onLoad` 到 `onShow` 之间的耗时 |
| `view_onshow_to_onready` | `onShow` 到 `onReady` 之间的耗时 |
例如,检索首屏渲染超过 2 秒的小程序页面:
```
source:miniprogram view_first_render:>2s
```
## 高级检索技巧
结合时间范围进行精确检索:
```
view_loading_time:>2s client_time:>1758253826081
```
检索结账页面的用户点击行为:
```
action_type:click view_url_path:/checkout/*
```
检索移动设备上加载时间超过 3 秒的视图:
```
device_type:mobile view_loading_time:>3s
```
检索中国地区发生错误的会话:
```
geo_country:China session_error_count:>0
```
## 最佳实践
确保多词短语的精确匹配
避免过于宽泛的检索条件
通过 AND/OR 操作符构建精确查询
减少输入错误,提高检索准确性
保存常用检索条件,提高重复查询的效率。
## 下一步
了解查看器核心功能
了解分布式追踪最佳实践
# RUM 查看器功能概览
Source: https://docs.flashduty.com/zh/rum/explorer/overview
掌握 Flashduty RUM 查看器的强大功能,通过可视化界面深入分析用户数据、性能指标和应用行为。
Flashduty RUM **查看器**(RUM Explorer)是一款强大的数据分析工具,旨在帮助开发者深入检查从应用程序收集的数据,并获取关于 RUM 事件的详细信息。通过直观的可视化界面,您可以全面了解用户行为、应用性能和系统健康状况。
## 核心功能
浏览和分析用户的完整会话路径,了解用户在应用中的行为模式
深入分析影响页面视图、资源加载或用户操作的性能问题
快速定位和诊断应用程序错误以及长时间运行的任务
通过搜索栏和可视化类型选择,对 RUM 事件进行精确过滤和筛选
## 价值与优势
| 优势 | 描述 |
| ---------- | ---------------------- |
| **数据驱动决策** | 基于真实用户数据做出产品优化和性能改进决策 |
| **问题快速定位** | 通过可视化界面快速识别性能瓶颈和用户体验问题 |
| **用户行为洞察** | 深入了解用户如何与您的应用交互,发现改进机会 |
| **全面监控覆盖** | 从页面加载到用户操作的全链路监控和分析 |
## 使用场景
分析页面加载时间、资源加载效率,识别性能瓶颈。
了解用户操作路径,发现交互设计中的问题。
快速定位应用错误发生的具体场景和上下文。
分析用户行为模式,为产品功能优化提供数据支持。
## 主要功能详解
使用顶部导航栏的应用选择器,可以选择特定应用程序并查看其所有 RUM 数据。
通过应用选择器,您可以快速切换不同应用的数据视图,专注于特定应用的性能和用户行为分析。
在 RUM 查看器中,您可以通过在搜索栏输入查询条件并选择可视化类型来搜索和过滤 RUM 事件。
点击数据项可查看数据详情,可将 RUM 事件以各种角度展示,帮助您发现关键信息。
* 查看数据关系,进行数据下钻或者查看数据父节点详情
* 通过查看资源的 trace,和已有的监控系统进行 trace 关联
## 按平台显示的视图指标
打开任一 View 的详情面板时,「性能」标签页的指标卡片会根据该 View 所属平台自适应展示,确保看到的是该平台真正具备的核心指标。
| 平台 | 性能指标卡片 |
| --------------------- | ----------------------------------------------------------------- |
| **浏览器(Web)** | `LCP`、`FCP`、`INP`、`CLS` |
| **原生(Android / iOS)** | `refresh_rate`、`cpu_ticks`、`memory` |
| **微信小程序** | `first_render`、`lcp`、`fcp`、`onload_to_onshow`、`onshow_to_onready` |
平台由 View 事件自身的 `source` 字段决定,无需手动切换。微信小程序场景下,`onload_to_onshow` 和 `onshow_to_onready` 对应小程序页面生命周期的两段耗时,可用于排查页面冷启动慢的原因。
EventTable 的列选择器也已经支持以下小程序专属字段作为可查询列:`view_first_render`、`view_onload_to_onshow`、`view_onshow_to_onready`。
## 保存视图
保存视图功能允许您将当前的查询状态保存为可复用的视图,方便快速切换不同的分析场景。每个账户最多可创建 **20 个**保存视图,视图仅您自己可见。
### 视图保存的内容
每个保存视图包含以下信息:
| 保存项 | 说明 |
| -------- | -------------------------------------------- |
| **时间范围** | 当前选择的时间筛选条件 |
| **查询类型** | 当前选择的事件类型(如 Sessions、Views、Actions、Errors 等) |
| **查询语句** | 搜索栏中的 DQL 筛选条件 |
| **自定义列** | 数据表格的列配置 |
### 视图操作
点击查看器顶部的视图菜单,选择「保存为新视图」,输入视图名称后确认即可创建。视图名称不可重复。
点击视图菜单,在视图列表中点击目标视图即可切换。切换后,查看器会自动恢复该视图保存的时间范围、查询类型、查询语句和列配置。
在视图列表中,点击目标视图右侧的操作菜单,选择「编辑视图」可修改视图名称。如果您修改了当前视图的查询条件,还可以通过「保存修改」将最新状态更新到视图中。
在视图列表或操作菜单中选择「删除视图」,确认后即可删除。删除当前正在使用的视图后,查看器会自动切换回默认视图。
在视图列表中,点击目标视图右侧的操作菜单,选择「复制链接」可获取该视图的分享链接。将链接分享给团队成员后,他们可以直接打开相同的查询视图。
通过操作菜单选择「切换默认视图」,查看器会清空所有筛选条件,恢复到初始状态。
## 下一步
掌握查询语法,精准定位数据
了解分布式追踪最佳实践
# 诊断指南
Source: https://docs.flashduty.com/zh/rum/performance/diagnosis-optimization
本文档详细介绍如何使用 Flashduty RUM 进行性能问题诊断和优化。
优化页面有助于根据真实用户流量数据识别浏览器性能问题的根本原因。通过浏览器指标(如核心网页指标和 Flashduty 自定义加载时间指标)排查页面加载缓慢的原因,这些指标可以从用户的角度评估完整页面的加载时间。
为了进行更深入的分析,优化页面提供了按用户人口统计(例如浏览器、地区和应用版本)的核心网页指标的详细拆分。您可以利用这些信息跟踪性能趋势,了解受影响最多的用户群体,精准优化。
## 诊断优化流程
您可导航至优化页面,该页面位于性能监控菜单下,选取待洞察的指标即可。您也可以通过在分析看板中查看对应的性能数据跳转至此功能。
选择页面和指标后,便可开始做性能数据洞察:
1. 点击指标卡片选择要洞察的指标(目前支持 LCP、FCP、INP、CLS)
2. 在「显示筛选细分」中选择一个组
3. 在不同的百分位数处评估指标(例如 p75 表示第 75 个百分位数值)
您可通过调整数据聚合方式或修改筛选条件,查看该指标在不同条件下的数据表现情况,从而推进诊断优化工作。
在问题诊断部分,您可以看到用户在页面上遇到的可能影响指标性能的资源和错误。
例如,对于最大内容绘制(LCP),您可以查看在触发 LCP 之前加载的资源。由于 LCP 是最大元素在页面上加载所需时间的指标,您可以从资源加载和解决错误两个方面进行问题诊断。
如果在资源分析阶段无法更准确地定位到关键信息,您可在事件样本区块中选取合适的事件样本进行更详细的上下文分析。
## 优化方向
资源加载分析面板展示当前视图下所有资源的详细加载信息,帮助您识别性能瓶颈。
您可以通过「全部资源」和「阻塞资源」两个选项卡切换查看范围:
* **全部资源**:展示视图中加载的所有资源
* **阻塞资源**:仅展示标记为 `blocking` 的渲染阻塞资源,这些资源会延迟页面的首次渲染
资源列表包含以下字段:
| 字段 | 说明 |
| ----------------- | ---------------------------------------------- |
| URL GROUP | 资源的 URL 路径分组 |
| TYPE | 资源类型(如 JS、CSS、Image 等) |
| AVG CLIENT SIZE | 平均客户端资源大小 |
| AVG TRANSFER SIZE | 平均传输大小(如传输大小明显小于客户端大小,说明部分采样命中了缓存) |
| AVG START TIME | 平均开始加载时间 |
| AVG DURATION | 平均加载耗时,并以色条可视化展示 DNS 解析、连接建立、首字节等待和下载四个阶段的耗时占比 |
将鼠标悬停在耗时色条上,可查看各阶段的具体耗时数值,帮助您判断是网络连接、服务器响应还是资源大小导致的加载缓慢。
* 关注可能导致问题的重复错误,这些异常也会影响页面性能
* 瀑布图显示了在捕获指标时事件的时间线
* 向下滚动可查看页面活动其余部分的上下文
* 使用左上角的下拉菜单选择另一个示例事件
* 单击展开瀑布中的任何事件以查看侧边面板
* 通过筛选事件类型和各筛选项来选取合适的事件集合进行问题分析
# 指标收集与上报
Source: https://docs.flashduty.com/zh/rum/performance/metrics-reporting
了解 Flashduty RUM 性能指标的收集方法、上报机制及配置说明。
Flashduty RUM 支持收集和上报 Web Vitals 相关的性能指标,帮助您全面监控和优化网站性能。通过这些指标,您可以了解用户在访问网站时的实际体验,并针对性地进行优化。
## Web Vitals 指标概览
Flashduty RUM 支持以下 [核心 Web Vitals 指标](https://web.dev/articles/vitals?hl=zh-cn):
| 指标 | 全称 | 说明 |
| -------- | -------- | --------------- |
| **LCP** | 最大内容绘制 | 衡量页面主要内容的加载性能 |
| **INP** | 交互到下一帧延迟 | 衡量整体交互响应性能 |
| **CLS** | 累计布局偏移 | 衡量视觉稳定性 |
| **FCP** | 首次内容绘制 | 衡量首次内容渲染时间 |
| **FID** | 首次输入延迟 | 衡量页面交互性能(辅助指标) |
| **TTFB** | 首次字节时间 | 衡量服务器响应速度(辅助指标) |
这些指标会在用户访问页面时自动收集,并通过 SDK 上报到 Flashduty 平台,您可以在分析看板中查看详细的性能数据。
对于在后台打开的页面(例如,在新标签页或无焦点的窗口中),不会收集到 INP 和 LCP 的数据。
## 指标计算方法
**计算方法:** 从页面开始加载(`navigationStart`)到最大可见内容元素(如图片、文本块)渲染完成的时间。
**用例:** 监控主页或关键页面内容加载速度,识别资源加载瓶颈。
**计算方法:** 测量从用户第一次导航到页面到页面内容的任何部分在屏幕上呈现的时间。
**用例:** 用于测量感知加载速度,有助于向用户保证某些事情正在发生。
**计算方法:** 测量所有用户交互(点击、轻触、键盘输入)到下一帧渲染的延迟时间。
**用例:** 评估页面整体交互响应性能,优化高延迟交互场景。
**计算方法:** 统计所有意外布局偏移的分数(偏移距离 × 影响区域)。
**用例:** 识别动态内容或广告导致的页面跳动问题。
**计算方法:** 从用户第一次交互开始到浏览器处理事件的时间差。
**用例:** 优化交互密集型页面(如表单、导航菜单)的响应速度。
## 监控单页应用 (SPA)
对于单页应用程序,RUM 浏览器 SDK 通过 `loading_type` 属性区分 `initial_load` 和 `route_change` 两种导航类型。
如果网页上的某个交互操作导致 URL 发生变化,但页面并未完全刷新,RUM SDK 会使用 `loading_type:route_change` 启动一个新的 `view`。
RUM 使用 [History API](https://developer.mozilla.org/zh-CN/docs/Web/API/History) 来跟踪 URL 的变化。
RUM SDK 会自动监控依赖哈希(`#`)导航的框架。SDK 会监听 `HashChangeEvent` 并发出一个新的 `view`。
来自 HTML 锚点且不影响当前视图上下文的事件将被忽略。
对于 SPA 应用,如需监控路由切换后的性能,建议使用自定义性能监控功能来测量特定组件或交互的性能指标。
## 自定义性能监控
### 组件级性能测量
使用 `customVital` API 监控特定组件或交互的性能,适用于:
* 关键组件渲染时间
* 用户交互响应时间
* 业务流程耗时
```javascript 测量组件渲染 theme={null}
// 开始计时
const ref = window.FC_RUM.startDurationVital("componentRendering", {
description: "login-form",
context: { clientId: "xxx", componentVersion: "1.0.0" },
});
// 结束计时
window.FC_RUM.stopDurationVital(ref);
```
```javascript 直接报告耗时 theme={null}
window.FC_RUM.addDurationVital("dropdownRendering", {
startTime: 1707755888000, // UNIX 时间戳(毫秒)
duration: 10000, // 耗时(毫秒)
});
```
### 性能时间点记录
使用 `addTiming` API 记录关键时间点,适用于:
* 关键元素加载(如首屏图片)
* 用户首次交互(如首次滚动)
* 业务节点时间戳
```javascript 记录首次滚动 theme={null}
document.addEventListener("scroll", function handler() {
document.removeEventListener("scroll", handler);
window.FC_RUM.addTiming("first_scroll");
});
```
```javascript 异步场景 theme={null}
document.addEventListener("scroll", function handler() {
document.removeEventListener("scroll", handler);
const timing = Date.now();
window.FC_RUM.onReady(() => {
window.FC_RUM.addTiming("first_scroll", timing);
});
});
```
## 注意事项
* 指标名称避免空格、特殊字符
* 使用描述性命名(如 `login_form_render`)
* 保持命名一致性
* 控制自定义指标数量
* 避免频繁计时
* 合理设置采样率
## 常见问题
* 检查慢加载资源(图片、脚本)
* 排查第三方脚本阻塞
* 分析长时间运行的 JavaScript
* 确认是否存在频繁的后台请求
* 检查长连接或流式请求的处理
* 使用 `excludedActivityUrls` 排除干扰
* 验证指标名称是否符合规范
* 确保计时器正确启停
* 检查异步场景的时间戳准确性
| 原因 | 说明 |
| -------- | ------------------------------------------------------ |
| 后台页面 | 页面在新标签页或无焦点窗口中打开,导致 INP 和 LCP 无法收集 |
| SPA 路由切换 | 在 `loading_type:route_change` 时,核心 Web Vitals 指标不会重新收集 |
| 引入方式 | 页面在 SDK 完全初始化前就已加载完成 |
| 页面生命周期 | 页面在指标收集完成前就被关闭或导航离开 |
| 浏览器兼容性 | 旧版本浏览器不支持某些 Web Vitals API |
| 页面无内容 | 页面没有可测量的内容元素(如空白页面) |
## 下一步
深入分析性能数据
学习问题诊断与优化方法
# 核心概念
Source: https://docs.flashduty.com/zh/rum/performance/overview
了解 Flashduty RUM 性能监控的核心概念、关键性能指标及计算方法,优化用户体验。
Flashduty RUM(真实用户监控)提供强大的工具,帮助您快速诊断和优化前端性能问题。通过性能监控模块可快速识别性能瓶颈、定位根因并实施优化措施,确保为用户提供流畅的体验。
## 核心功能
自动收集并分析关键性能指标(如 FCP、LCP、CLS、FID 等),提供全面的性能数据视图
监控和分析静态资源(如 JS、CSS、图片等)的加载性能,识别加载缓慢的资源
追踪和分析后端 API 调用的性能表现,包括响应时间、成功率等指标
提供全面的性能问题诊断能力,包括性能瓶颈分析、资源加载优化建议等
## 价值与优势
| 优势 | 描述 |
| ---------- | ------------------------- |
| **提升用户体验** | 通过优化网站性能,减少页面加载时间,提高用户满意度 |
| **提高转化率** | 改善网站性能,提升用户留存率和转化率 |
| **数据驱动决策** | 基于性能数据做出优化决策,持续改进产品性能 |
## 使用场景
识别并解决网站性能瓶颈,提升整体性能表现。
分析并优化静态资源加载,提高页面加载速度。
监控和优化后端 API 性能,提升接口响应速度。
通过性能数据了解用户使用体验,针对性地改进产品。
## 性能监控流程
Flashduty RUM 的性能优化分为三个关键阶段:
快速发现性能问题的触发点是诊断的第一步。Flashduty RUM 提供以下方式帮助您识别问题:
* **数据分析**:通过「应用管理 - 数据分析」模块,查看核心性能指标的数据趋势
* **用户反馈**:通过用户报告(如页面加载缓慢或交互卡顿)发现潜在问题
* **异常检测**:观察异常趋势,如资源加载失败率升高或 API 响应时间延长
**初步评估:**
* **影响范围**:确定问题影响的用户群体(例如特定地区、设备或浏览器)
* **严重程度**:评估问题对用户体验的直接影响
* **业务影响**:分析问题对关键业务指标(如转化率或用户留存)的影响
Flashduty RUM 提供丰富的性能数据和上下文信息:
**核心性能数据:**
* **页面加载指标**:包括 LCP、FCP、TTI
* **资源加载时间**:分析图片、脚本、CSS 等资源的加载耗时
* **JavaScript 性能**:监控脚本执行时间和阻塞渲染的脚本
* **网络请求**:记录 API 请求的延迟、成功率和错误率
**上下文信息:**
* **用户环境**:浏览器类型、设备型号、操作系统和网络状况
* **错误日志**:捕获 JavaScript 错误、网络错误和资源加载失败的详细信息
* **系统资源**:分析 CPU 使用率、内存占用和 DOM 操作频率
通过可视化工具和分析功能,将性能问题分类并精准定位根因。
### 常见问题分类
| 问题类型 | 典型表现 | 可能原因 | 关键指标 |
| ----------------- | ------------ | -------------------------------- | ------------- |
| **页面加载缓慢** | 白屏时间长、首屏渲染慢 | 资源体积过大、阻塞渲染的脚本或 CSS、服务器响应慢 | LCP, FCP, TTI |
| **交互响应延迟** | 点击无反应、操作卡顿 | JavaScript 执行时间长、事件监听过多、DOM 操作频繁 | FID, INP, TBT |
| **资源加载异常** | 图片/脚本加载失败、超时 | CDN 配置错误、网络不稳定、资源路径错误 | 资源加载时间, 失败率 |
| **JavaScript 错误** | 功能失效、控制台报错 | 代码逻辑错误、浏览器兼容性问题、内存泄漏 | 错误率, 内存使用 |
| **网络连接问题** | 请求超时、连接中断 | API 响应慢、网络质量差、跨域配置错误 | 请求延迟, 连接成功率 |
## 问题定位工具
性能瀑布图展示页面加载的完整时间线,帮助您识别瓶颈。
**关键时间点:**
* **导航开始**:用户发起页面请求的时间
* **DNS 查询**:域名解析耗时
* **TCP 连接**:建立服务器连接的耗时
* **首字节时间(TTFB)**:接收服务器响应的第一个字节的耗时
* **DOM 完成**:页面 DOM 结构加载完成的时间
**资源加载分析:**
* **关键路径**:识别影响页面渲染的关键资源
* **阻塞资源**:发现阻塞渲染的脚本或样式表
* **加载顺序**:优化资源加载优先级
* **资源大小**:检查是否存在体积过大的资源
Flashduty RUM 捕获并分类前端错误,提供详细的上下文信息。
**错误类型:**
* JavaScript 运行时错误(如未捕获的异常或语法错误)
* 网络请求错误(如 API 超时或 4xx/5xx 错误)
* 资源加载错误(如图片或脚本加载失败)
* 框架相关错误(如 React 或 Vue 的组件渲染错误)
**错误上下文:**
* **错误堆栈**:提供详细的调用栈信息
* **用户操作序列**:重现触发错误的操作路径
* **环境信息**:包括浏览器、设备和网络状态
* **相关性能数据**:关联错误与性能指标的变化
## 优化建议
定位问题根因后,您可以根据分析结果实施优化:
压缩资源、优化 critical CSS、启用 CDN
减少 JavaScript 执行时间、优化事件监听器
检查 CDN 配置、确保资源路径正确
修复代码逻辑、添加错误边界、优化内存使用
## 下一步
了解指标收集与上报机制
深入分析性能数据
学习问题诊断与优化方法
# 数据分析指南
Source: https://docs.flashduty.com/zh/rum/performance/performance-analysis
了解如何分析和利用 Flashduty RUM 收集的性能数据,包括性能指标分析、用户体验评估和性能优化建议。
性能数据分析页面通过分析真实用户流量数据来帮助识别浏览器性能问题的根本原因。使用核心网页指标(Core Web Vitals)和自定义加载时间指标等浏览器指标来排查页面加载缓慢的原因。这些指标从用户角度评估完整的页面加载时间。
## 访问性能分析
导航至性能监控菜单,您可以通过列表或树状视图,从不同的视角分析性能体验。
切换至列表视图,通过页面排序查看 Top 页面下各指标的数据情况:
* 通过指标数据前面的颜色标识可快速查看指标全貌,定位到待提升指标
* Hover 至每个指标可查看该指标在标准下所处的当前水位
* 点击每一行记录,可查看该页面下的指标详情
切换至树状视图,可以从某个指标视角下查看待优化的资源列表:
* 切换不同的指标,查看其分布情况
* 查看「良好」、「较差」、「一般」分类下的资源分布与占比,快速定位问题资源
* 点击区块所代表的页面后,可查看该页面下的指标详情,方便进一步做问题诊断
## 数据分析维度
通过全局筛选器,可以从不同维度对页面性能进行分析,从而洞察性能数据趋势变化:
| 维度 | 说明 |
| ---- | --------- |
| 浏览器 | 按浏览器类型筛选 |
| 连接状态 | 按网络连接状态筛选 |
| 设备情况 | 按设备类型筛选 |
| 地理位置 | 按地理位置信息筛选 |
性能分析页面同样支持侧栏和全屏两种查看模式。点击某个页面记录后,默认以侧栏形式展示指标详情;您可以点击展开按钮切换到全屏模式,获得更完整的数据展示和诊断空间。
## 下一步
学习问题诊断与优化方法
# 应用管理
Source: https://docs.flashduty.com/zh/rum/quickstart/app-management
学习如何在 Flashduty 平台创建和管理 RUM 应用,包括应用创建、配置和权限管理
## 概述
RUM 应用是承载前端性能监控数据的容器,用于采集、存储和分析用户在前端应用中的真实体验数据。一个应用代表一个被监控的前端项目,可以是网站、移动应用或单页应用等。
我们建议按照业务系统或应用来创建 RUM 应用,例如:官网、商城、管理后台等。
每个应用拥有独立的 `applicationId` 和 `clientToken`,用于识别数据来源并确保数据安全。应用创建后,您需要将 SDK 集成到您的前端代码中,以开始数据采集和监控。
## 应用权限
为了满足不同业务场景的数据安全需求,RUM 应用提供了灵活的访问级别设置:
| 访问级别 | 可见范围 | 适用场景 |
| ------ | ------------------------ | ------ |
| **公开** | 账户内所有用户可见,可查看数据和处理 Issue | 通用业务应用 |
| **私有** | 仅创建者、账户管理员和主体账户可见 | 敏感业务数据 |
私有应用中,其他成员若需查看内容,可以通过分享故障链接的方式临时授权访问。
## 创建应用
通过 RUM 产品引导页面,您可以快速创建一个应用:
选择应用对应的前端技术类型,目前支持 **JavaScript (JS)、Android、iOS、HarmonyOS、Flutter、微信小程序、Electron**。
指定该应用的管理团队。
团队所属成员对该应用拥有全部操作权限,非团队成员对该应用的配置仅可只读访问。
默认情况下,自动启用用户地理位置数据采集。如需禁用客户端 IP 或地理位置数据的自动采集,请关闭地理信息收集开关。
详见 [数据收集](/zh/rum/others/data-collection)。
默认情况下,自动开启告警通知,方便您及时处理错误。
详见 [Issue 告警](/zh/rum/error-tracking/issue-alerts)。
## SDK 配置
您可以在 **应用配置 > SDK 配置** 中修改参数并实时预览初始化代码,以便快速接入 SDK。
控制台为不同平台提供了详细的集成引导:
* **JavaScript(Web)**:配置服务名等参数后,实时预览 `flashcatRum.init()` 初始化代码
* **Android**:展示完整的集成步骤,包括添加 Gradle 依赖(`cloud.flashcat:dd-sdk-android-core` 和 `cloud.flashcat:dd-sdk-android-rum`)、在 `Application.onCreate()` 中初始化 SDK 并启用 RUM,以及可选的 WebView 追踪集成
* **iOS**:展示完整的集成步骤,包括添加 Swift Package Manager 依赖(`fc-sdk-ios`,版本 0.3.0 起)、在 `AppDelegate.didFinishLaunchingWithOptions` 中初始化 SDK 并启用 RUM,以及可选的 WebView 追踪集成
* **Flutter**:Flutter SDK 封装了 Android/iOS 原生 SDK,一次集成即可同时监控两端,详见 [Flutter SDK 接入](/zh/rum/sdk/flutter/sdk-integration)
* **微信小程序**:通过表单填写 `env`、`service`、`version`、`sessionSampleRate` 后,实时预览基于 `@flashcatcloud/miniprogram-rum` 的 `flashcatRum.init()` 初始化代码(参见下方「微信小程序 SDK 配置助手」)
* **Electron**:提供分步接入向导——主进程安装 `@flashcatcloud/electron-sdk` 并在 `app.whenReady()` 中完成初始化(必须在创建任何窗口之前,顺序不对时 SDK 不报错但采集不到数据);如需采集窗口内的页面浏览、用户操作、网络请求与 JS 错误,渲染进程可选接入 `@flashcatcloud/browser-rum`,数据经 IPC 桥交由主进程统一上报;使用 Vite / webpack / esbuild 打包主进程时,还可加入对应插件以保留 SDK 的运行时依赖。详见 [Electron SDK 接入](/zh/rum/sdk/electron/sdk-integration)
每个平台的 SDK 配置页面都会自动填入当前应用的 `applicationId` 和 `clientToken`,您可以直接复制代码到项目中使用。
在应用管理中修改 SDK 配置并不会实时生效到已集成的客户端。所有配置更改需要在您的前端代码中更新并重新部署才能生效。
### 服务定义
服务是一个独立的、可部署的代码存储库,它映射到一组页面。
如果您的应用程序是作为一个整体构建的,那么您的 RUM 应用只需要一个服务名称。
```javascript theme={null}
flashcatRum.init({
applicationId: 'YOUR_APP_ID',
clientToken: 'YOUR_CLIENT_TOKEN',
service: 'my-web-app' // 单一服务名称
});
```
如果您的浏览器应用程序由多个独立存储库构建,请为不同模块设置不同的服务名称。
```javascript theme={null}
// 主应用
flashcatRum.init({
service: 'main-app'
});
// 子应用 A
flashcatRum.init({
service: 'module-a'
});
```
### 微信小程序 SDK 配置助手
当应用类型选择为「微信小程序」时,**应用配置 > SDK 配置** 会展示专门的小程序集成向导:左侧填写表单参数,右侧实时生成可直接复制的初始化代码。
#### 表单字段
| 字段 | 说明 | 校验规则 | 默认值 |
| ------------------- | -------------------- | --------------------- | ------- |
| `env` | 环境变量,例如 `prod`、`dev` | 仅支持英文、数字、下划线;最长 24 字符 | 无 |
| `service` | 服务名称,所有事件默认带上此标签 | 仅支持英文、数字、下划线;最长 24 字符 | 无 |
| `version` | 版本号,便于数据分析时筛选 | 仅支持英文、数字、`.`;最长 24 字符 | `1.0.0` |
| `sessionSampleRate` | 会话采样率(百分比) | 整数,范围 `0 ~ 100` | `10` |
表单字段填写完毕后,无需点击保存——预览代码会随输入实时更新。`applicationId` 和 `clientToken` 由系统自动填入,无需手动配置。
#### 两步集成
在小程序项目中执行以下命令安装 SDK,并通过微信开发者工具完成 npm 构建:
```bash theme={null}
npm install @flashcatcloud/miniprogram-rum
```
点击右侧代码块右上角的复制按钮,将生成的初始化代码粘贴到小程序的 `app.js`:
```typescript theme={null}
import { flashcatRum } from '@flashcatcloud/miniprogram-rum';
flashcatRum.init({
applicationId: "",
clientToken: "",
service: "",
env: "",
version: "1.0.0",
sessionSampleRate: 10
});
```
完整的 SDK 能力、采集开关和事件上报机制请参见 [微信小程序 SDK 接入](/zh/rum/sdk/wechat-miniprogram/sdk-integration)。
## Link 集成
Link 集成允许您把 RUM 事件与外部系统关联起来,例如链路追踪平台、日志检索、对象存储中的崩溃日志包或内部排障系统。配置完成后,RUM 会根据事件类型和事件上下文生成跳转链接,并在事件详情中展示 **关联 Link**。
Link 集成位于应用详情的 **Link 集成** 页签,适用于所有应用类型。具有 **RUM 应用更新** 权限的成员可以新增、编辑、启用、禁用或删除链接配置。
### 内置 Tracing
内置 Tracing 是 Link 集成中的默认卡片,用于把资源事件中的 `trace_id` 跳转到您的后端链路追踪系统。
在 **Link 集成** 页签中找到 **Tracing** 卡片,填写链路追踪系统的跳转链接。链接中可以使用 `${trace_id}` 变量,RUM 会在展示链接时替换为资源事件中的实际 Trace ID。
例如:`https://your-tracing-system.com/trace/${trace_id}`
保存跳转链接后,打开 **Tracing** 开关。未填写跳转链接时,开关不可开启。
内置 Tracing 仅匹配资源事件,并且只有事件包含 `trace_id` 时才会展示。跳转链接必须以 `http://` 或 `https://` 开头。
### 添加外部链接
除内置 Tracing 外,您可以为不同事件类型添加自定义外部链接。
在 **Link 集成** 页签中点击 **添加外部链接**,填写链接名称和跳转链接模板。
选择该链接适用的事件类型。当前支持 **崩溃、错误、视图、操作、资源、会话**。
崩溃属于错误事件:选择 **错误** 会匹配普通错误和崩溃;选择 **崩溃** 只匹配崩溃事件。
在 **跳转链接模板** 中插入变量,例如 `${session_id}`、`${error_id}` 或 `${trace_id}`。页面会使用示例值实时预览最终 URL,便于您确认模板是否符合外部系统的查询格式。
| 配置项 | 说明 | 规则 |
| ------ | ----------------------------- | ----------------------------- |
| 链接名称 | 在 RUM 事件详情中展示的外部系统名称 | 必填 |
| 适用事件类型 | 控制该链接在哪些 RUM 事件上展示 | 至少选择一个事件类型 |
| 跳转链接模板 | 外部系统 URL,可包含 `${variable}` 变量 | 必须以 `http://` 或 `https://` 开头 |
| 单条开关 | 控制该外部链接是否生效 | 关闭后不再展示该链接 |
### 可用变量
Link 集成会从当前事件上下文中提取变量并替换到 URL 模板中。
| 变量 | 说明 | 常见适用事件 |
| ------------------- | ------------- | ----------------- |
| `${session_id}` | 会话 ID | 会话、视图、操作、错误、资源 |
| `${view_id}` | 视图 ID | 视图、操作、错误、资源 |
| `${action_id}` | 操作 ID | 操作 |
| `${error_id}` | 错误 ID | 错误、崩溃 |
| `${resource_id}` | 资源 ID | 资源 |
| `${trace_id}` | 链路追踪 ID | 资源、内置 Tracing |
| `${application_id}` | RUM 应用 ID | 所有事件 |
| `${service}` | 服务名称 | 采集了 `service` 的事件 |
| `${version}` | 版本 | 采集了 `version` 的事件 |
| `${env}` | 环境 | 采集了 `env` 的事件 |
| `${usr_id}` | 用户 ID | 采集了用户信息的事件 |
| `${usr_name}` | 用户名 | 采集了用户信息的事件 |
| `${usr_email}` | 用户邮箱 | 采集了用户信息的事件 |
| `${start_time}` | 当前事件详情查询的开始时间 | 查看器事件详情 |
| `${end_time}` | 当前事件详情查询的结束时间 | 查看器事件详情 |
建议把可选变量放在查询参数中,例如 `https://logs.example.com/search?session=${session_id}&error=${error_id}`。当某个查询参数只包含缺失变量时,RUM 会在生成链接时省略该参数;路径中的缺失变量会保留为原始 `${variable}` 文本。
### 查看关联 Link
当事件匹配已启用的链接配置时,您可以在以下位置打开外部系统:
* **RUM 查看器事件详情**:右上角显示 **关联 Link** 下拉入口,适用于会话、视图、操作、错误和资源等事件详情
* **错误事件详情**:详情区域内嵌展示匹配的关联 Link 卡片,支持复制或打开链接
* **Issue 错误样本**:在错误样本下方展示匹配的关联 Link,便于从 Issue 直接跳转到日志、链路追踪或其他排障系统
## 隐私设置
隐私设置允许您控制 RUM SDK 采集的用户隐私数据范围,以满足不同地区的数据合规要求。
| 设置项 | 说明 | 关联字段 |
| ---------- | ------------------------ | ------------------------------------------ |
| **地理位置信息** | 控制是否采集用户的国家、省份、城市等地理位置信息 | `@geo_country`、`@geo_province`、`@geo_city` |
| **IP 地址** | 控制是否采集用户的 IPv4 和 IPv6 地址 | `@geo_ip_v4`、`@geo_ip_v6` |
关闭地理位置或 IP 地址采集后,相关筛选和分析维度将不再可用。请根据业务需求和合规要求谨慎调整。
## 删除应用
如果您不再需要某个应用,可以在应用详情的「基础信息」页签底部找到删除按钮。
删除应用后:
* 不会再接收任何新事件
* 应用的 Client Token 将被立即撤销
* 已采集的 RUM 事件数据仍可手动导出,或通过联系支持团队恢复已删除的应用
此操作需要 **RUM 应用删除** 权限。
## 下一步
了解如何接入 RUM SDK
了解 SDK 的高级配置选项
查看和分析 RUM 数据
了解如何在微信小程序中接入 RUM SDK
# Flashduty RUM 入门指南
Source: https://docs.flashduty.com/zh/rum/quickstart/quickstart
了解如何快速开始使用 Flashduty RUM 进行前端性能监控
## 快速上手
使用 Flashduty RUM 只需简单几步,即可开始监控您的前端应用性能。
### 基本流程
### 接入步骤
RUM 应用是承载前端性能监控数据的容器。我们建议按照业务系统或应用来创建,例如:官网、商城、管理后台等。
1. 进入 RUM 应用列表页,点击 **创建 RUM 应用**
2. 输入应用名称、管理团队、访问级别和告警配置
3. 点击确认创建即可
前往 [应用管理](/zh/rum/quickstart/app-management) 了解更多配置选项。
创建好 RUM 应用后,您需要将 SDK 集成到您的应用中。
1. 在应用详情页获取 SDK 接入配置信息
2. 根据您的应用类型,选择对应的接入文档
适用于 Web 网页应用,支持 CDN 和 npm 两种接入方式
适用于 Android 原生应用,支持 Gradle 依赖接入
适用于 iOS 原生应用,支持 CocoaPods 和 SPM 接入
SDK 集成完成后,系统将自动收集以下数据:
* **页面性能指标**:加载时间、首屏时间等
* **资源加载性能**:JS、CSS、图片等资源
* **用户行为数据**:点击、滚动等交互
* **错误和异常信息**:JavaScript 异常、网络错误
* **网络请求性能**:API 调用耗时和状态
数据通常在 2-5 分钟内显示在控制台中。
### 功能体验
在 RUM 控制台中,您可以使用以下功能:
查看实时性能数据,分析页面加载瓶颈
监控 JavaScript 异常,快速定位问题根因
回放用户操作,还原问题发生场景
自定义查询和分析监控数据
## 下一步
* [数据收集](/zh/rum/others/data-collection) - 了解数据类型和存储策略
* [高级配置](/zh/rum/sdk/web/advanced-config) - 自定义 SDK 行为
* [问题排查](/zh/rum/sdk/web/faq) - 解决常见问题
# Android SDK 高级配置
Source: https://docs.flashduty.com/zh/rum/sdk/android/advanced-config
深入配置 Android RUM SDK 的高级功能,包括自定义事件、用户追踪、采样控制和数据安全
**关于依赖和包名的说明**
Flashduty Android SDK 完全兼容 Datadog 开源协议,代码中的 import 语句使用 `com.datadog.android.*` 包名。您可以无缝复用 Datadog 生态的文档、示例和最佳实践,同时享受 Flashduty 平台的服务。
Android RUM SDK 提供丰富的高级配置选项,帮助您根据业务需求定制数据收集和上下文信息。
**支持的配置场景:**
* 丰富用户会话 - 添加自定义视图、操作、资源和错误信息
* 保护敏感数据 - 屏蔽个人身份信息等敏感数据
* 关联用户会话 - 将用户会话与内部用户标识关联
* 控制数据量 - 通过采样和事件过滤优化数据收集
* 增强上下文 - 为数据添加自定义属性
## 丰富用户会话
### 自定义视图
当使用 `ActivityViewTrackingStrategy` 或 `FragmentViewTrackingStrategy` 时,RUM SDK 会自动追踪视图。您也可以在视图变为可见或可交互时手动发送自定义 RUM 视图。
```kotlin theme={null}
import com.datadog.android.rum.GlobalRumMonitor
fun onResume() {
GlobalRumMonitor.get().startView(viewKey, viewName, attributes)
}
fun onPause() {
GlobalRumMonitor.get().stopView(viewKey, attributes)
}
```
```java theme={null}
import com.datadog.android.rum.GlobalRumMonitor;
public void onResume() {
GlobalRumMonitor.get().startView(viewKey, viewName, attributes);
}
public void onPause() {
GlobalRumMonitor.get().stopView(viewKey, attributes);
}
```
**参数说明:**
* `viewKey` (String) - 视图的唯一标识符,同一个 `viewKey` 用于调用 `startView()` 和 `stopView()`
* `viewName` (String) - 视图的名称
* `attributes` (`Map`) - 附加到视图的属性(可选)
### 自定义操作
除了自动追踪的用户交互,您还可以追踪特定的自定义用户操作(如点击、滑动、点赞)。
```kotlin theme={null}
import com.datadog.android.rum.GlobalRumMonitor
import com.datadog.android.rum.RumActionType
fun onUserInteraction() {
GlobalRumMonitor.get().addAction(
RumActionType.TAP,
name,
attributes
)
}
```
```java theme={null}
import com.datadog.android.rum.GlobalRumMonitor;
import com.datadog.android.rum.RumActionType;
public void onUserInteraction() {
GlobalRumMonitor.get().addAction(
RumActionType.TAP,
name,
attributes
);
}
```
| 类型 | 描述 | 使用场景 |
| ---------------------- | ----- | ------- |
| `RumActionType.TAP` | 点击操作 | 按钮、图标点击 |
| `RumActionType.SCROLL` | 滚动操作 | 列表、页面滚动 |
| `RumActionType.SWIPE` | 滑动操作 | 滑动切换、手势 |
| `RumActionType.CLICK` | 单击操作 | 通用点击 |
| `RumActionType.CUSTOM` | 自定义操作 | 业务特定操作 |
### 自定义资源
除了自动追踪的资源,您还可以手动追踪特定的自定义资源(如网络请求、第三方库加载)。
```kotlin theme={null}
import com.datadog.android.rum.GlobalRumMonitor
import com.datadog.android.rum.RumResourceKind
fun loadResource() {
GlobalRumMonitor.get().startResource(resourceKey, method, url, attributes)
}
fun resourceLoadSuccess() {
GlobalRumMonitor.get().stopResource(
resourceKey, statusCode, size,
RumResourceKind.NATIVE, attributes
)
}
fun resourceLoadError() {
GlobalRumMonitor.get().stopResourceWithError(
resourceKey, statusCode, message, source, throwable
)
}
```
```java theme={null}
import com.datadog.android.rum.GlobalRumMonitor;
import com.datadog.android.rum.RumResourceKind;
public void loadResource() {
GlobalRumMonitor.get().startResource(resourceKey, method, url, attributes);
}
public void resourceLoadSuccess() {
GlobalRumMonitor.get().stopResource(
resourceKey, statusCode, size,
RumResourceKind.NATIVE, attributes
);
}
public void resourceLoadError() {
GlobalRumMonitor.get().stopResourceWithError(
resourceKey, statusCode, message, source, throwable
);
}
```
| 类型 | 描述 | 适用场景 |
| ---------- | ------------- | ------- |
| `BEACON` | 信标请求 | 统计上报 |
| `FETCH` | Fetch 请求 | 现代异步请求 |
| `XHR` | XHR 请求 | 传统 Ajax |
| `DOCUMENT` | 文档资源 | HTML 文档 |
| `IMAGE` | 图片资源 | 图片加载 |
| `JS` | JavaScript 资源 | JS 文件 |
| `FONT` | 字体资源 | 字体文件 |
| `CSS` | CSS 资源 | 样式文件 |
| `MEDIA` | 媒体资源 | 音视频文件 |
| `NATIVE` | 原生资源 | 原生模块加载 |
| `OTHER` | 其他资源 | 未分类资源 |
### 自定义错误
要记录特定错误,当异常发生时通知 RUM SDK:
```kotlin theme={null}
import com.datadog.android.rum.GlobalRumMonitor
GlobalRumMonitor.get().addError(
message,
source,
throwable,
attributes
)
```
```java theme={null}
import com.datadog.android.rum.GlobalRumMonitor;
GlobalRumMonitor.get().addError(
message,
source,
throwable,
attributes
);
```
更多错误上报详情,请参阅 [Android 异常上报](/zh/rum/error-tracking/erro-reporting/android)。
### 自定义计时
除了 RUM SDK 默认的性能指标,您还可以使用 `addTiming` API 测量关键操作的耗时。计时是相对于当前 RUM 视图开始时间的偏移量。
```kotlin theme={null}
import com.datadog.android.rum.GlobalRumMonitor
fun onHeroImageLoaded() {
GlobalRumMonitor.get().addTiming("hero_image")
}
```
```java theme={null}
import com.datadog.android.rum.GlobalRumMonitor;
public void onHeroImageLoaded() {
GlobalRumMonitor.get().addTiming("hero_image");
}
```
设置计时后,可通过 `@view.custom_timings.` 访问,例如 `@view.custom_timings.hero_image`。
### 设置用户信息
RUM SDK 支持设置标准用户信息。
```kotlin theme={null}
import com.datadog.android.rum.GlobalRumMonitor
GlobalRumMonitor.get().setUserInfo(
id = "1234",
name = "John Doe",
email = "john@doe.com"
)
```
```java theme={null}
import com.datadog.android.rum.GlobalRumMonitor;
GlobalRumMonitor.get().setUserInfo(
"1234",
"John Doe",
"john@doe.com",
null
);
```
当前仅支持设置用户标准字段:`id`、`name`、`email`、`anonymous_id`;其他用户属性不支持。如有需求,可以在 `context` 字段进行配置。
## 事件和数据管理
### 清除所有数据
使用 `clearAllData` 清除当前存储在 SDK 中的所有未发送数据:
```kotlin theme={null}
import com.datadog.android.Datadog
Datadog.clearAllData()
```
```java theme={null}
import com.datadog.android.Datadog;
Datadog.clearAllData();
```
### 停止数据收集
使用 `stopInstance` 停止收集数据并清除所有本地数据:
```kotlin theme={null}
import com.datadog.android.Datadog
Datadog.stopInstance()
```
```java theme={null}
import com.datadog.android.Datadog;
Datadog.stopInstance();
```
调用 `stopInstance()` 后,SDK 将完全停止工作,需要重新初始化才能恢复数据收集。
### 控制事件批量上传
RUM SDK 会自动批量上传事件。您可以通过配置参数控制批量上传的行为:
```kotlin theme={null}
import com.datadog.android.core.configuration.Configuration
import com.datadog.android.core.configuration.UploadFrequency
val configuration = Configuration.Builder(
clientToken = clientToken,
env = environmentName,
variant = appVariantName
)
.setBatchSize(batchSize)
.setUploadFrequency(UploadFrequency.FREQUENT)
.build()
```
```java theme={null}
import com.datadog.android.core.configuration.Configuration;
import com.datadog.android.core.configuration.UploadFrequency;
Configuration configuration = new Configuration.Builder(
clientToken, environmentName, appVariantName
)
.setBatchSize(batchSize)
.setUploadFrequency(UploadFrequency.FREQUENT)
.build();
```
| 频率 | 描述 | 适用场景 |
| ---------- | ---- | ------------ |
| `FREQUENT` | 频繁上传 | 实时性要求高的场景 |
| `AVERAGE` | 平均上传 | 默认值,平衡性能和实时性 |
| `RARE` | 少量上传 | 节省流量和电量 |
### 设置远程日志阈值
您可以为远程记录的消息定义最低日志级别。低于该级别的日志不会发送到 Flashduty:
```kotlin theme={null}
import com.datadog.android.log.Logs
import com.datadog.android.log.LogsConfiguration
import android.util.Log
val logsConfig = LogsConfiguration.Builder()
.setRemoteSampleRate(100f)
.setRemoteLogThreshold(Log.WARN)
.build()
Logs.enable(logsConfig)
```
```java theme={null}
import com.datadog.android.log.Logs;
import com.datadog.android.log.LogsConfiguration;
import android.util.Log;
LogsConfiguration logsConfig = new LogsConfiguration.Builder()
.setRemoteSampleRate(100f)
.setRemoteLogThreshold(Log.WARN)
.build();
Logs.enable(logsConfig);
```
设置 `Log.WARN` 阈值后,只有 WARN、ERROR 级别的日志会被上传,DEBUG 和 INFO 级别的日志将被过滤。
## 追踪自定义全局属性
除了由 RUM SDK 自动捕获的默认属性外,您还可以向 RUM 事件添加额外的上下文信息,例如自定义属性。
**自定义属性的用途:**
* 根据业务信息(如购物车状态、用户等级、广告活动)过滤和分组用户行为
* 跟踪特定用户的浏览路径
* 了解哪些用户受错误影响最大
* 监控关键用户的性能表现
### 追踪用户会话
要识别用户会话,在初始化 SDK 后使用 `setUserInfo` API:
```kotlin theme={null}
import com.datadog.android.rum.GlobalRumMonitor
GlobalRumMonitor.get().setUserInfo(
id = "1234",
name = "John Doe",
email = "john@doe.com"
)
```
```java theme={null}
import com.datadog.android.rum.GlobalRumMonitor;
GlobalRumMonitor.get().setUserInfo("1234", "John Doe", "john@doe.com", null);
```
当前仅支持设置用户标准字段:`id`、`name`、`email`、`anonymous_id`;其他用户属性不支持。如有需求,可以在 `context` 字段进行配置。
**参数说明:**
* `id` (String) - 唯一用户标识符
* `name` (String) - 用户友好名称,默认在 RUM UI 中显示
* `email` (String) - 用户电子邮件,若无名称则显示邮件
* 以上属性均为可选,建议至少提供一个
### 追踪属性
全局属性会被附加到所有 RUM 事件中,用于添加通用的上下文信息。
**添加全局属性:**
```kotlin theme={null}
import com.datadog.android.rum.GlobalRumMonitor
GlobalRumMonitor.get().addAttribute("key", "value")
```
```java theme={null}
import com.datadog.android.rum.GlobalRumMonitor;
GlobalRumMonitor.get().addAttribute("key", "value");
```
**删除全局属性:**
```kotlin theme={null}
import com.datadog.android.rum.GlobalRumMonitor
GlobalRumMonitor.get().removeAttribute("key")
```
```java theme={null}
import com.datadog.android.rum.GlobalRumMonitor;
GlobalRumMonitor.get().removeAttribute("key");
```
## 追踪 Widgets
Widgets 不会自动追踪。要监控 Widget 的交互,需要手动调用 API。
```kotlin theme={null}
import com.datadog.android.rum.GlobalRumMonitor
import com.datadog.android.rum.RumActionType
fun onWidgetClicked() {
GlobalRumMonitor.get().addAction(
RumActionType.TAP,
"widget_clicked",
mapOf("widget_name" to "HomeWidget")
)
}
```
```java theme={null}
import com.datadog.android.rum.GlobalRumMonitor;
import com.datadog.android.rum.RumActionType;
import java.util.HashMap;
import java.util.Map;
public void onWidgetClicked() {
Map attributes = new HashMap<>();
attributes.put("widget_name", "HomeWidget");
GlobalRumMonitor.get().addAction(
RumActionType.TAP,
"widget_clicked",
attributes
);
}
```
## 初始化参数
在初始化 Flashduty Android SDK 时,您可以使用 `Configuration.Builder` 配置多种选项。
### 自动追踪视图
要自动追踪视图(Activities、Fragments),在初始化时使用 `useViewTrackingStrategy`:
```kotlin theme={null}
import com.datadog.android.rum.RumConfiguration
import com.datadog.android.rum.tracking.ActivityViewTrackingStrategy
val rumConfig = RumConfiguration.Builder(applicationId)
.useViewTrackingStrategy(ActivityViewTrackingStrategy(true))
.build()
```
```java theme={null}
import com.datadog.android.rum.RumConfiguration;
import com.datadog.android.rum.tracking.ActivityViewTrackingStrategy;
RumConfiguration rumConfig = new RumConfiguration.Builder(applicationId)
.useViewTrackingStrategy(new ActivityViewTrackingStrategy(true))
.build();
```
| 策略 | 参数 | 描述 | 适用场景 |
| -------------------------------- | ------------------------------- | ------------------------ | --------------------- |
| `ActivityViewTrackingStrategy` | `trackExtras` | 追踪每个 Activity 为一个单独的视图 | 传统 Activity 架构 |
| `FragmentViewTrackingStrategy` | `trackArguments` | 追踪每个 Fragment 为一个单独的视图 | Fragment 为主的应用 |
| `MixedViewTrackingStrategy` | `trackExtras`, `trackArguments` | 同时追踪 Activity 和 Fragment | 混合架构应用 |
| `NavigationViewTrackingStrategy` | `navigationViewId` | 追踪 Navigation 组件的目的地 | 使用 Jetpack Navigation |
### 自动追踪网络请求
要自动追踪 HTTP 网络请求,请参考 [SDK 接入指南](./sdk-integration#开启分布式-trace-追踪) 中的 OkHttp 拦截器配置。
### 自动追踪 Apollo GraphQL 请求
如果您使用 Apollo GraphQL 客户端进行网络调用,可以启用自动追踪。
在应用的 `build.gradle` 文件中添加依赖:
```groovy build.gradle theme={null}
dependencies {
implementation "cloud.flashcat:dd-sdk-android-apollo:"
}
```
请访问 [Maven Central 版本页面](https://central.sonatype.com/artifact/cloud.flashcat/dd-sdk-android-core/versions) 获取最新版本号。
```kotlin theme={null}
import com.apollographql.apollo.ApolloClient
import com.apollographql.apollo.network.okHttpClient
import com.datadog.android.apollo.DatadogApolloInterceptor
val apolloClient = ApolloClient.Builder()
.serverUrl("GraphQL endpoint")
.addInterceptor(DatadogApolloInterceptor())
.okHttpClient(okHttpClient)
.build()
```
```java theme={null}
import com.apollographql.apollo.ApolloClient;
import com.datadog.android.apollo.DatadogApolloInterceptor;
ApolloClient apolloClient = new ApolloClient.Builder()
.serverUrl("GraphQL endpoint")
.addInterceptor(new DatadogApolloInterceptor())
.okHttpClient(okHttpClient)
.build();
```
Flashduty 追踪头将自动添加到您的 GraphQL 请求中,使其能够被追踪。
**限制说明:**
* 仅支持 Apollo 版本 **4**
* 仅追踪 `query` 和 `mutation` 类型的操作,不追踪 `subscription` 操作
**启用 GraphQL Payload 发送(可选):**
```kotlin theme={null}
DatadogApolloInterceptor(sendGraphQLPayloads = true)
```
```java theme={null}
new DatadogApolloInterceptor(true)
```
### 自动追踪长任务
在主线程上执行的长时间运行的操作可能会影响应用的视觉性能和响应性。SDK 可以自动检测并追踪长任务。
```kotlin theme={null}
import com.datadog.android.rum.RumConfiguration
// 使用默认阈值(100ms)
val rumConfig = RumConfiguration.Builder(applicationId)
.trackLongTasks(durationThreshold)
.build()
// 自定义阈值(250ms)
val rumConfig = RumConfiguration.Builder(applicationId)
.trackLongTasks(250L)
.build()
```
```java theme={null}
import com.datadog.android.rum.RumConfiguration;
// 使用默认阈值(100ms)
RumConfiguration rumConfig = new RumConfiguration.Builder(applicationId)
.trackLongTasks(durationThreshold)
.build();
// 自定义阈值(250ms)
RumConfiguration rumConfig = new RumConfiguration.Builder(applicationId)
.trackLongTasks(250L)
.build();
```
默认阈值为 **100ms**。您可以根据应用性能要求调整此阈值。
## 修改或丢弃 RUM 事件
要在批量处理之前修改 RUM 事件的某些属性,或完全丢弃某些事件,请在初始化时提供 `EventMapper` 的实现。
```kotlin theme={null}
import com.datadog.android.rum.RumConfiguration
val rumConfig = RumConfiguration.Builder(applicationId)
.setErrorEventMapper(rumErrorEventMapper)
.setActionEventMapper(rumActionEventMapper)
.setResourceEventMapper(rumResourceEventMapper)
.setViewEventMapper(rumViewEventMapper)
.setLongTaskEventMapper(rumLongTaskEventMapper)
.build()
```
```java theme={null}
import com.datadog.android.rum.RumConfiguration;
RumConfiguration rumConfig = new RumConfiguration.Builder(applicationId)
.setErrorEventMapper(rumErrorEventMapper)
.setActionEventMapper(rumActionEventMapper)
.setResourceEventMapper(rumResourceEventMapper)
.setViewEventMapper(rumViewEventMapper)
.setLongTaskEventMapper(rumLongTaskEventMapper)
.build();
```
### 可修改的事件属性
当实现 `EventMapper` 接口时,每种事件类型只有部分属性可以修改:
| 属性键 | 描述 |
| --------------- | -------------- |
| `view.referrer` | 链接到页面初始视图的 URL |
| `view.url` | 视图的 URL |
| `view.name` | 视图的名称 |
| 属性键 | 描述 |
| -------------------- | -------------- |
| `action.target.name` | 目标名称 |
| `view.referrer` | 链接到页面初始视图的 URL |
| `view.url` | 视图的 URL |
| `view.name` | 视图的名称 |
| 属性键 | 描述 |
| -------------------- | -------------- |
| `error.message` | 错误消息 |
| `error.stack` | 错误的堆栈跟踪 |
| `error.resource.url` | 资源的 URL |
| `view.referrer` | 链接到页面初始视图的 URL |
| `view.url` | 视图的 URL |
| `view.name` | 视图的名称 |
| 属性键 | 描述 |
| --------------- | -------------- |
| `resource.url` | 资源的 URL |
| `view.referrer` | 链接到页面初始视图的 URL |
| `view.url` | 视图的 URL |
| `view.name` | 视图的名称 |
| 属性键 | 描述 |
| --------------- | -------------- |
| `view.referrer` | 链接到页面初始视图的 URL |
| `view.url` | 视图的 URL |
| `view.name` | 视图的名称 |
如果从 `EventMapper` 实现中返回 `null`,则事件将被丢弃,不会发送到 Flashduty。
### 示例:丢弃敏感错误
```kotlin theme={null}
val rumConfig = RumConfiguration.Builder(applicationId)
.setErrorEventMapper { errorEvent ->
if (errorEvent.error.message?.contains("sensitive_data") == true) {
null // 丢弃包含敏感数据的错误
} else {
errorEvent
}
}
.build()
```
```java theme={null}
RumConfiguration rumConfig = new RumConfiguration.Builder(applicationId)
.setErrorEventMapper(errorEvent -> {
if (errorEvent.error.message != null &&
errorEvent.error.message.contains("sensitive_data")) {
return null; // 丢弃包含敏感数据的错误
} else {
return errorEvent;
}
})
.build();
```
## 获取 RUM Session ID
检索 RUM Session ID 对于故障排查很有帮助。您可以将 Session ID 附加到支持请求、电子邮件或错误报告中,以便支持团队在 Flashduty 中找到用户会话。
```kotlin theme={null}
import com.datadog.android.rum.GlobalRumMonitor
GlobalRumMonitor.get().getCurrentSessionId { sessionId ->
currentSessionId = sessionId
}
```
```java theme={null}
import com.datadog.android.rum.GlobalRumMonitor;
GlobalRumMonitor.get().getCurrentSessionId(sessionId -> {
currentSessionId = sessionId;
});
```
您可以在运行时访问 RUM Session ID,而无需等待 `sessionStarted` 事件。
## 采样控制
默认情况下,RUM 会收集所有会话的数据。您可以通过 `sessionSampleRate` 参数设置采样率来减少收集的会话数量。
```kotlin theme={null}
import com.datadog.android.rum.RumConfiguration
val rumConfig = RumConfiguration.Builder(applicationId)
.setSessionSampleRate(90.0f) // 采集 90% 的会话
.build()
```
```java theme={null}
import com.datadog.android.rum.RumConfiguration;
RumConfiguration rumConfig = new RumConfiguration.Builder(applicationId)
.setSessionSampleRate(90.0f) // 采集 90% 的会话
.build();
```
采样率范围:**0.0 - 100.0**
* `100.0` - 收集所有会话(默认)
* `50.0` - 收集 50% 的会话
* `0.0` - 不收集任何会话
被采样丢弃的会话将不收集任何页面视图及其相关遥测数据。
## 用户跟踪同意
为遵守 GDPR、CCPA 等隐私法规,RUM 允许在初始化时设置用户跟踪同意状态。
### 同意状态说明
| 状态 | 行为 | 使用场景 |
| ----------------------------- | -------------------- | --------- |
| `TrackingConsent.GRANTED` | 开始收集数据并发送到 Flashduty | 用户已同意数据收集 |
| `TrackingConsent.NOT_GRANTED` | 不收集任何数据 | 用户拒绝数据收集 |
| `TrackingConsent.PENDING` | 收集数据但不发送 | 等待用户确认 |
如果初始化时使用 `TrackingConsent.PENDING`,SDK 将开始收集数据,但在同意状态更改为 `GRANTED` 之前不会发送。
### 更改同意状态
您可以通过 `setTrackingConsent` API 在初始化后更改同意状态:
```kotlin theme={null}
import com.datadog.android.Datadog
import com.datadog.android.privacy.TrackingConsent
Datadog.setTrackingConsent(TrackingConsent.GRANTED)
```
```java theme={null}
import com.datadog.android.Datadog;
import com.datadog.android.privacy.TrackingConsent;
Datadog.setTrackingConsent(TrackingConsent.GRANTED);
```
## 最佳实践
* 确保在适当的生命周期方法中调用 `startView` 和 `stopView`,避免视图重复追踪
* 为每个视图使用唯一的 `viewKey`
* 使用自定义资源追踪时,确保每个 `startResource` 都有对应的 `stopResource` 或 `stopResourceWithError` 调用
* 避免追踪内部资源或过于频繁的请求
* 修改事件时,只有表格中列出的属性可以修改,其他属性的修改将被忽略
* 返回 `null` 可丢弃整个事件
* 合理设置采样率和批量上传频率,平衡数据量与性能开销
* 避免在事件回调中执行耗时操作
## 相关文档
了解如何接入 Android SDK
了解 SDK 收集的数据类型
了解 SDK 兼容性要求
# Android SDK 兼容性
Source: https://docs.flashduty.com/zh/rum/sdk/android/compatible
了解 Android RUM SDK 支持的系统版本、开发工具、框架和第三方库兼容性
本文档说明 Android RUM SDK 支持的 Android 系统版本、开发平台及开发环境要求。
## 系统要求
| 类别 | 支持范围 |
| ----------------- | ------------------------- |
| **最低 Android 版本** | Android 6.0(API level 23) |
| **最高 Android 版本** | 当前最新 Android 版本 |
| **支持的设备类型** | Android 手机、平板、Android TV |
不支持 Android 6.0(API level 23)以下的系统版本。
## 支持的平台
Android 手机应用完整支持
Android 平板应用完整支持
Android TV 应用完整支持
## 开发语言
| 开发语言 | 是否支持 | 推荐程度 |
| ------ | ---- | ---- |
| Java | ✅ | 完全支持 |
| Kotlin | ✅ | 推荐使用 |
## SDK 版本
| SDK 主版本 | 支持的 Android API | 状态 |
| -------- | --------------- | -------- |
| **v3.x** | API 23+ | 当前版本(推荐) |
| v2.x | API 23+ | 维护中 |
| v1.x | - | 已废弃 |
已废弃版本不建议用于新的集成项目,可能不再提供功能更新或问题修复。
## 构建工具链要求
| 要求项 | 说明 |
| ------------- | ----------------------------------- |
| **AndroidX** | 必须使用 AndroidX,不支持旧版 Support Library |
| **构建系统** | Gradle |
| **Kotlin 版本** | 需与 AndroidX 生态版本保持兼容 |
## 功能兼容性
Android TV 应用与普通 Android 应用具有相同的最低系统版本要求(API 23+)。
所有 RUM 功能在 Android TV 上都可正常使用。
* 支持 Jetpack Compose 的监控能力
* 具体兼容性取决于应用所使用的 Compose 版本
* 推荐使用最新稳定版 Compose
Compose 应用中的导航、性能和用户交互都可以被自动追踪。
* 支持 WebView 监控功能(需显式开启)
* 兼容性取决于系统 WebView 版本
* 详见 [SDK 接入指南 - WebView 集成](/zh/rum/sdk/android/sdk-integration#webview-集成)
WebView 监控需要额外的配置和依赖。
提供对常见 Android 库的集成支持:
| 第三方库 | 支持状态 | 说明 |
| -------- | ---- | ------------- |
| OkHttp | ✅ | 自动追踪 HTTP 请求 |
| Retrofit | ✅ | 通过 OkHttp 拦截器 |
| Glide | ✅ | 图片加载监控 |
| Timber | ✅ | 日志集成 |
具体兼容性取决于对应第三方库本身的系统要求。
## 版本更新策略
SDK 遵循语义化版本控制(Semantic Versioning):
| 更新类型 | 版本格式 | 兼容性 | 说明 |
| -------- | ------ | ----- | ---------------- |
| **主版本** | v3.0.0 | 可能不兼容 | 可能包含破坏性更改,需要代码调整 |
| **次版本** | v3.1.0 | 向后兼容 | 新增功能,保持向后兼容 |
| **补丁版本** | v3.1.1 | 完全兼容 | Bug 修复,完全向后兼容 |
建议定期更新 SDK 到最新稳定版本以获得最佳性能和安全性。
## 快速参考
Android 6.0(API level 23)
手机、平板、Android TV
Java、Kotlin
SDK v3.x
## 相关文档
了解如何集成 Android SDK
配置 SDK 的高级功能
了解 SDK 收集的数据类型
# Android SDK 数据收集
Source: https://docs.flashduty.com/zh/rum/sdk/android/data-collection
全面了解 Flashduty Android RUM SDK 自动收集的性能指标、事件属性和设备信息
Flashduty Android RUM SDK 默认自动收集所有 RUM 事件的多个指标和属性。您还可以通过 API 添加自定义属性以扩展默认数据集。
## 隐私合规与权限说明
Flashduty Android RUM SDK 仅为真实用户体验监控、错误定位、性能分析和网络请求分析收集必要的运行时信息。SDK 自身声明的 Android 权限如下:
| 权限 | 用途 |
| ----------------------------------------- | ----------------------- |
| `android.permission.INTERNET` | 上传 RUM、Trace、Log 等观测数据 |
| `android.permission.ACCESS_NETWORK_STATE` | 获取网络连接状态,用于标记事件发生时的网络环境 |
SDK 自身不会声明或要求 `READ_PHONE_STATE`、`ACCESS_FINE_LOCATION`、`ACCESS_COARSE_LOCATION` 等敏感权限。
### 不采集的设备标识
Android RUM SDK 不会读取或上报以下设备唯一标识:
| 标识 | 是否采集 | 说明 |
| ------------------------------------------------- | ---- | ----------------------------------------------- |
| Android ID / SSAID (`Settings.Secure.ANDROID_ID`) | 否 | SDK 不读取 Android ID |
| IMEI / MEID / 设备号 | 否 | SDK 不调用 `getDeviceId()`、`getImei()`、`getMeid()` |
| 设备序列号 | 否 | SDK 不读取 `Build.SERIAL` 或 `Build.getSerial()` |
| OAID / 广告 ID | 否 | SDK 不读取 OAID、GAID 或其他广告标识 |
| 手机号码、通讯录、短信、相册 | 否 | SDK 不访问这些系统数据 |
RUM 默认可生成一个匿名用户 ID,用于跨会话关联同一匿名用户。该 ID 是 SDK 随机生成的 UUID,并存储在应用本地数据目录中,不来自 Android ID、IMEI、OAID 或广告 ID。您可以在 RUM 配置中关闭匿名用户追踪。
### 会采集的系统上下文
SDK 会自动附加以下系统上下文,帮助排查性能、崩溃和网络问题:
| 数据类别 | 示例 | 用途 |
| ------ | -------------------------------------------------- | ------------------------------------------------------ |
| 应用信息 | 应用包名、版本名称、构建版本号、环境、服务名 | 区分应用、版本和环境 |
| 设备信息 | 设备品牌、型号、设备类型、CPU 架构、屏幕数量 | 分析设备兼容性和性能差异 |
| 系统信息 | Android 版本、系统主版本、系统构建号、语言、时区 | 定位系统版本或区域相关问题 |
| 网络信息 | 网络类型、蜂窝网络制式、运营商名称、上下行带宽、信号强度 | 分析网络质量对体验的影响 |
| RUM 事件 | View、Action、Resource、Error、Long Task、启动耗时 | 还原用户旅程、定位错误和性能瓶颈 |
| 用户信息 | `usr.id`、`usr.name`、`usr.email`、`usr.anonymous_id` | 仅在业务主动调用 API 设置时附加;其他用户属性不支持。如有需求,可以在 `context` 字段进行配置 |
本文档列出的“地理位置”字段由 Flashduty 后端根据客户端请求 IP 推断,不是 Android 客户端读取系统定位。SDK 不调用 GPS、基站定位或融合定位 API,也不需要定位权限。
## 应用启动指标
Flashduty 自动收集以下应用启动性能指标:
| 指标 | 描述 | 测量范围 |
| ----------------------------- | --------------- | ----------------------------- |
| **cold\_start\_duration** | 冷启动持续时间 | 从应用进程创建到首个 Activity 渲染完成 |
| **warm\_start\_duration** | 温启动持续时间 | 应用进程已存在,从 Activity 开始到渲染完成 |
| **hot\_start\_duration** | 热启动持续时间 | 应用和 Activity 都在内存中,从恢复到渲染完成 |
| **activity\_start\_duration** | Activity 启动持续时间 | 从 `onCreate` 到首帧绘制完成 |
| **is\_pre\_warmed** | 预热启动标识 | 布尔值,指示应用是否通过预热启动(Android 11+) |
**启动类型说明:**
* **冷启动** - 应用首次启动或进程被终止后启动,需要加载所有资源并初始化应用状态
* **温启动** - 应用进程在内存中,但 Activity 需要重新创建
* **热启动** - 应用和 Activity 都在内存中,只需将 Activity 带回前台
## Views 监控
View 代表用户在应用中看到的唯一屏幕。每个 View 开始时会创建一个新的 RUM 事件,并在 View 的整个生命周期内更新该事件。
View 会收集其生命周期内发生的所有资源、操作、错误和长任务的相关信息。
### 自动追踪策略
在 Android 中,Activities 和 Fragments 被视为 View。SDK 提供以下自动追踪策略:
| 策略 | 描述 | 适用场景 |
| ---------------------------------- | ------------------------- | ----------------- |
| **ActivityViewTrackingStrategy** | 基于 Activity 生命周期追踪 | 传统 Activity 架构 |
| **FragmentViewTrackingStrategy** | 基于 Fragment 生命周期追踪 | Fragment 为主的应用 |
| **MixedViewTrackingStrategy** | 同时追踪 Activity 和 Fragment | 混合架构应用 |
| **NavigationViewTrackingStrategy** | 适用于 Jetpack Navigation 组件 | 使用 Navigation 的应用 |
您也可以通过手动调用 `RumMonitor.startView()` 和 `RumMonitor.stopView()` 来自定义 View 追踪。
## 默认属性
RUM SDK 为所有事件自动附加默认属性,帮助您了解用户设备、网络状态和应用上下文。
| 属性名 | 类型 | 描述 |
| --------------------- | ------ | ------------------------------------------------------ |
| `application.id` | string | Flashduty 应用 ID。 |
| `application.name` | string | 应用包名(例如 `com.example.app`)。 |
| `application.version` | string | 应用版本名称。 |
| `application.build` | string | 应用构建版本号。 |
| `session.id` | string | 唯一会话 ID,用于将用户旅程中的事件分组。 |
| `session.type` | string | 会话类型:`user`。 |
| `view.id` | string | 为每个 View 生成的唯一 ID。 |
| `view.url` | string | View 的规范化 URL(Activity 或 Fragment 的类名)。 |
| `view.name` | string | 可自定义的 View 名称。 |
| `env` | string | 应用的环境名称(例如 `prod`、`dev`)。 |
| `service` | string | 服务名称,用于区分应用的不同模块或微服务。 |
| `version` | string | 应用版本。 |
| `sdk_version` | string | Flashduty SDK 版本。 |
| `date` | number | 事件发生的时间戳(epoch 毫秒) |
| `type` | string | 事件类型(如 `view`、`resource`、`action`、`error`、`long_task`) |
以下属性与设备相关,在所有 RUM 事件中自动收集:
| 属性名 | 类型 | 描述 |
| ----------------------- | ------ | -------------------------------- |
| `device.type` | string | 设备类型,如 `mobile`、`tablet`、`tv` 等。 |
| `device.name` | string | 设备商业名称(例如 `Samsung Galaxy S21`)。 |
| `device.model` | string | 设备型号(例如 `SM-G991B`)。 |
| `device.brand` | string | 设备品牌(例如 `Samsung`)。 |
| `device.architecture` | string | 设备架构(例如 `arm64-v8a`) |
| `device.marketing_name` | string | 设备的市场营销名称 |
以下网络相关属性在所有 RUM 事件中自动收集:
| 属性名 | 类型 | 描述 |
| ------------------------------------ | ------ | ----------------------------------------------- |
| `connectivity.status` | string | 设备网络可达性状态(`connected`、`not_connected`、`maybe`)。 |
| `connectivity.interfaces` | array | 可用网络接口列表(例如 `wifi`、`cellular`、`ethernet`)。 |
| `connectivity.cellular.technology` | string | 蜂窝网络技术类型(例如 `LTE`、`5G`) |
| `connectivity.cellular.carrier_name` | string | 运营商名称(例如 `中国移动`) |
以下操作系统相关属性在所有 RUM 事件中自动收集:
| 属性名 | 类型 | 描述 |
| ------------------ | ------ | --------------------------- |
| `os.name` | string | 操作系统名称(例如 `Android`)。 |
| `os.version` | string | 操作系统版本(例如 `13`)。 |
| `os.version_major` | string | 操作系统主版本号(例如 `13`) |
| `os.build` | string | 系统构建号(例如 `TQ2A.230505.002`) |
RUM 可以从用户的 IP 地址推断出地理位置信息:
| 属性名 | 类型 | 描述 |
| ----------------- | ------ | ---------- |
| `geo.country` | string | 国家名称 |
| `geo.country_iso` | string | 国家的 ISO 代码 |
| `geo.city` | string | 城市名称 |
地理位置信息由 Flashduty 后端根据客户端 IP 地址推断,不会在 Android 客户端收集精确的 GPS 位置,也不需要定位权限。
您可以通过 `setUser()` API 设置用户信息,这些信息会被附加到所有 RUM 事件中:
| 属性名 | 类型 | 描述 |
| ------------------ | ------ | --------- |
| `usr.id` | string | 用户的唯一标识符 |
| `usr.name` | string | 用户的友好名称 |
| `usr.email` | string | 用户的电子邮件地址 |
| `usr.anonymous_id` | string | 匿名用户标识符 |
当前仅支持以上用户标准字段,其他用户属性不支持。如有需求,可以在 `context` 字段进行配置。
## 事件特定属性
除了默认属性外,不同类型的 RUM 事件还会收集特定的指标和属性。
| 属性名 | 类型 | 描述 |
| -------------------- | ------ | ------------ |
| `session.id` | string | 唯一会话 ID。 |
| `session.type` | string | 会话类型:`user`。 |
| `session.has_replay` | bool | 会话是否包含会话重放录制 |
| `session.is_active` | bool | 会话是否处于活动状态 |
View 事件包含以下特定属性和性能指标:
| 属性名 | 类型 | 描述 |
| ----------------------------- | ---------- | --------------------------------------------------------------- |
| `view.id` | string | 每个 View 的唯一 ID。 |
| `view.name` | string | View 的自定义名称。 |
| `view.url` | string | View 的 URL(Activity 或 Fragment 类名)。 |
| `view.time_spent` | number(ns) | 用户在此 View 上花费的时间。 |
| `view.loading_time` | number(ns) | View 加载完成所需的时间。 |
| `view.loading_type` | string | View 加载类型:`initial_load`、`activity_display`、`fragment_display`。 |
| `view.first_contentful_paint` | number(ns) | 首次内容绘制时间(仅适用于 API 29+)。 |
| `view.action.count` | number | View 中收集的所有操作的数量。 |
| `view.resource.count` | number | View 中收集的所有资源的数量。 |
| `view.error.count` | number | View 中收集的所有错误的数量。 |
| `view.long_task.count` | number | View 中收集的所有长任务的数量。 |
| `view.crash.count` | number | View 中收集的所有崩溃的数量 |
| `view.is_active` | bool | View 是否仍处于活动状态 |
Resource 事件表示应用中的网络请求。收集的属性包括:
| 属性名 | 类型 | 描述 |
| ------------------------------ | ---------- | ----------------------------------------------------------------- |
| `resource.id` | string | 资源的唯一标识符。 |
| `resource.type` | string | 资源类型(例如 `xhr`、`fetch`、`image`、`css`、`js`、`font`、`media`、`other`)。 |
| `resource.url` | string | 资源的 URL。 |
| `resource.method` | string | HTTP 方法(例如 `GET`、`POST`)。 |
| `resource.status_code` | number | HTTP 响应状态码。 |
| `resource.duration` | number(ns) | 加载资源所花费的总时间。 |
| `resource.size` | number | 资源大小(字节)。 |
| `resource.dns.duration` | number(ns) | DNS 解析时间(`domainLookupEnd - domainLookupStart`)。 |
| `resource.connect.duration` | number(ns) | 建立连接的时间(`connectEnd - connectStart`)。 |
| `resource.ssl.duration` | number(ns) | TLS 握手时间(`connectEnd - secureConnectionStart`),仅适用于 HTTPS。 |
| `resource.first_byte.duration` | number(ns) | 等待首字节响应的时间(`responseStart - requestStart`)。 |
| `resource.download.duration` | number(ns) | 下载响应的时间(`responseEnd - responseStart`)。 |
| `resource.redirect.duration` | number(ns) | 后续 HTTP 重定向所花费的时间(`redirectEnd - redirectStart`)。 |
| `resource.provider.name` | string | 资源提供商名称,默认为 `unknown`。 |
| `resource.provider.domain` | string | 资源提供商域名 |
| `resource.provider.type` | string | 资源提供商类型(如 `first-party`、`cdn`、`ad`、`analytics`) |
错误事件收集异常和崩溃信息,错误消息和堆栈跟踪会被自动包含:
| 属性名 | 类型 | 描述 |
| ---------------- | ------ | --------------------------------------------------------- |
| `error.source` | string | 错误来源(例如 `webview`、`logger`、`network`、`source`、`console`)。 |
| `error.type` | string | 错误类型或错误代码。 |
| `error.message` | string | 简洁、人类可读的单行错误消息。 |
| `error.stack` | string | 堆栈跟踪或错误的补充信息。 |
| `error.issue_id` | string | 错误问题的唯一标识符。 |
| `error.category` | string | 错误的高级分类,可能的值:`ANR`(应用无响应)、`Exception`(异常)。 |
| `error.file` | string | 发生错误的文件名(用于错误追踪问题)。 |
| `error.line` | number | 发生错误的行号 |
| `error.is_crash` | bool | 指示该错误是否导致应用崩溃 |
**网络错误:**
网络错误包含有关失败的 HTTP 请求的信息,并收集以下属性:
| 属性名 | 类型 | 描述 |
| -------------------------------- | ------ | ----------------------------------------------- |
| `error.resource.status_code` | number | HTTP 响应状态码。 |
| `error.resource.method` | string | HTTP 方法(例如 `POST`、`GET`)。 |
| `error.resource.url` | string | 资源 URL。 |
| `error.resource.provider.name` | string | 资源提供商名称,默认为 `unknown`。 |
| `error.resource.provider.domain` | string | 资源提供商域名 |
| `error.resource.provider.type` | string | 资源提供商类型(如 `first-party`、`cdn`、`ad`、`analytics`) |
Action 代表用户与应用的交互(例如点击、滑动、滚动)。
**计时属性:**
| 属性名 | 类型 | 描述 |
| ------------------------ | ---------- | -------------- |
| `action.loading_time` | number(ns) | 操作的加载时间。 |
| `action.long_task.count` | number | 此操作收集的所有长任务数量。 |
| `action.resource.count` | number | 此操作收集的所有资源数量 |
| `action.error.count` | number | 此操作收集的所有错误数量 |
**基本属性:**
| 属性名 | 类型 | 描述 |
| -------------------- | ------ | ---------------------------------------------------- |
| `action.id` | string | 用户操作的 UUID |
| `action.type` | string | 用户操作类型(如 `tap`、`scroll`、`swipe`、`application_start`) |
| `action.name` | string | 用户操作的名称 |
| `action.target.name` | string | 用户交互的元素,仅适用于自动收集的操作 |
## 数据存储与安全
### 本地存储机制
在数据上传到 Flashduty 之前,会以明文形式存储在应用的缓存目录中。
**存储位置:**
```
/data/data//cache/com.flashcat.rum/
```
**安全保护:**
* 缓存文件夹受 Android 应用沙箱保护
* 在大多数设备上,其他应用无法读取这些数据
**安全注意事项:**
* 如果移动设备已 root 或有人篡改 Linux 内核,存储的数据可能会变得可读
* 敏感数据不应包含在 RUM 事件中,或者应在发送前通过 `EventMapper` 进行混淆或过滤
## 数据上传机制
Android RUM SDK 采用批处理方式上传事件,在保证数据传输的同时最小化对用户体验的影响。
### 批处理流程
SDK 将未压缩的事件追加到批次文件中,使用 TLV 编码格式(Tag-Length-Value)。
当批次关闭时:
* 读取批次文件并提取事件
* 对 RUM 事件进行去重优化(删除冗余的 View 事件)
* 构建特定于每个追踪的有效载荷
使用 gzip 压缩数据,减少网络流量和上传时间。
### 上传触发条件
批次在以下任一情况下会被上传:
| 触发条件 | 说明 |
| -------- | ------------------ |
| **文件大小** | 批次文件大小达到阈值(例如 4MB) |
| **事件数量** | 批次中的事件数量达到阈值 |
| **应用状态** | 应用切换到后台 |
| **定时上传** | 定期上传(例如每 5 秒) |
### 上传策略
**智能上传机制:**
* **网络优化** - 优先通过 WiFi 上传,移动网络也支持
* **电量管理** - 确保不会过度消耗设备电量
* **失败重试** - 上传失败时批次会保留在本地,直到成功发送
* **数据压缩** - 使用 gzip 压缩,减少网络流量
## Direct Boot 模式支持
如果您的应用支持 Direct Boot 模式(在设备解锁前启动),请注意:
在设备解锁前捕获的数据将**不会被记录**,因为此时凭据加密存储尚不可用。
Flashduty SDK 会在设备解锁后开始收集数据。如果您需要在 Direct Boot 模式下收集数据,请确保使用设备加密存储而非凭据加密存储。
## 相关文档
了解如何集成 Android SDK
配置自定义属性、采样和事件过滤
了解 SDK 兼容性要求
# Android SDK 性能影响
Source: https://docs.flashduty.com/zh/rum/sdk/android/performance-impact
了解 Flashduty Android RUM SDK 对应用 CPU、内存、启动时间、APK 大小和网络使用的影响,以及性能优化建议。
## 概述
在将任何 SDK 集成到 Android 应用时,了解其性能影响对于维护良好的用户体验至关重要。Flashduty RUM SDK 在设计时充分考虑了性能因素,并提供透明的测量数据,帮助您做出明智的集成决策。
SDK 采用异步处理和批量上报机制,避免阻塞主线程,确保不影响应用的 UI 响应性能。
## 性能基准测试
为了评估 SDK 对应用性能的实际影响,我们在典型使用场景下进行了性能基准测试。测试中启用了以下 SDK 功能模块:
* `dd-sdk-android-rum`:RUM 核心功能
* `dd-sdk-android-trace`:链路追踪
* `dd-sdk-android-okhttp`:网络请求追踪
SDK 使用默认配置进行初始化,并模拟常见用户操作(如页面浏览、滚动列表、网络请求等)。
### 测试结果
| 指标 | 集成 SDK 后 | 未集成 SDK | 影响 |
| ---------- | ------------------------------ | -------- | ----------------------- |
| 峰值 CPU 使用率 | \~27% | \~25% | +2% |
| 峰值内存使用 | \~435 MB | \~437 MB | 基本持平 |
| 应用启动时间 | \~245 ms | \~230 ms | +15 ms |
| APK 大小 | 基础 RUM 约 +410 KB;全量模块约 +3.6 MB | - | 取决于接入模块、R8 配置和 ABI 打包方式 |
| 网络使用 | \~70 KB 发送 / \~20 KB 接收 | - | 根据事件量变化 |
以上数据为典型场景下的参考值,实际影响会因应用复杂度、设备性能和 SDK 配置不同而有所差异。
### 性能影响详解
SDK 对 CPU 的影响主要来自:
* 事件收集和处理
* 数据批处理和压缩
* 网络请求上报
SDK 采用异步处理和批量上报机制,避免阻塞主线程,确保不影响应用的 UI 响应性能。
SDK 使用固定大小的内存缓冲区存储待上报的事件数据,不会随时间无限增长。过旧的数据会被自动清理,确保不会占用过多内存。
SDK 初始化过程经过优化,启动时间影响控制在毫秒级。
建议在 `Application.onCreate()` 中尽早初始化 SDK,以便捕获完整的应用启动过程。
SDK 采用模块化设计,您可以根据需要只引入必要的功能模块:
| 模块 | 说明 |
| ------------------------ | ----------- |
| `dd-sdk-android-rum` | RUM 核心功能 |
| `dd-sdk-android-trace` | 链路追踪 |
| `dd-sdk-android-okhttp` | OkHttp 网络追踪 |
| `dd-sdk-android-webview` | WebView 追踪 |
只引入必要的模块可以最小化对 APK 大小的影响。
实验室测量数据如下,供评估接入成本时参考:
| 接入口径 | 构建类型 | APK 增量 | 说明 |
| ------------------------------------------------------- | -------------------------------- | -------- | ------------------------------- |
| `dd-sdk-android-core` + `dd-sdk-android-rum` | Release,开启 R8 / minify | 约 410 KB | 基础 RUM 接入口径 |
| `dd-sdk-android-core` + `dd-sdk-android-rum` | Debug | 约 1.3 MB | Debug 包未经过 R8 裁剪,增量更大 |
| `core` + `rum` + `trace` + `webview` + `okhttp` + `ndk` | Release,开启 R8 / minify,多 ABI APK | 约 3.6 MB | 主要增量来自 NDK 模块携带的多 ABI native so |
| `core` + `rum` + `trace` + `webview` + `okhttp` + `ndk` | Debug,多 ABI APK | 约 4.6 MB | 当前 Android demo 的全量接入口径 |
以上包体积数据基于 Flashduty Android SDK 0.4.0 和 Android demo 测得,统计口径为 APK 文件大小增量。实际结果会受原 App 已有依赖、R8 裁剪规则、是否使用 App Bundle / ABI split、以及是否接入 Trace、WebView、OkHttp、NDK 等模块影响。
SDK 采用以下策略优化网络使用:
* **批量上报**:事件先缓存到本地,批量发送以减少网络请求次数
* **数据压缩**:上报数据经过压缩处理,减少传输流量
* **智能调度**:根据网络状态和电量情况智能调度上报时机
## 性能优化建议
如果您对性能有特殊要求,可以考虑以下优化措施:
通过配置采样率减少收集的事件数量:
```kotlin theme={null}
val rumConfig = RumConfiguration.Builder(applicationId)
.setSessionSampleRate(80f) // 采样 80% 的会话
.build()
```
只启用必要的追踪功能:
```kotlin theme={null}
val rumConfig = RumConfiguration.Builder(applicationId)
.trackUserInteractions(false) // 禁用用户交互追踪
.trackLongTasks(false) // 禁用长任务追踪
.build()
```
调整批量上报的大小和频率,根据应用场景优化网络使用。
## 离线数据存储
SDK 在设备离线时会将数据存储到本地,存储空间使用受到严格限制:
* 使用固定大小的磁盘缓存
* 过期数据自动清理
* 不会因缓存数据过多影响设备存储空间
## 相关文档
了解如何接入 SDK
了解如何配置 SDK 的高级功能
了解 SDK 收集的数据类型
# Android SDK 接入
Source: https://docs.flashduty.com/zh/rum/sdk/android/sdk-integration
快速集成 Android RUM SDK,实时监控应用性能、错误和用户行为
Flashduty Android RUM SDK 支持 **Android 6.0 (API level 23)**
及以上版本。通过集成 SDK,您可以实时监控 Android 应用的性能、错误和用户行为。
**关于依赖和包名的说明**
Flashduty Android SDK 完全兼容 Datadog 开源协议,代码中的 import 语句使用 `com.datadog.android.*` 包名。您可以无缝复用 Datadog 生态的文档、示例和最佳实践,同时享受 Flashduty 平台的服务。
## 接入步骤
在您的应用模块的 `build.gradle` 文件中添加 Flashduty SDK 依赖:
```groovy build.gradle theme={null}
dependencies {
implementation "cloud.flashcat:dd-sdk-android-core:"
implementation "cloud.flashcat:dd-sdk-android-rum:"
// 必需:SDK 运行时依赖 Gson 与 OkHttp,需由宿主应用提供
implementation "com.google.code.gson:gson:2.8.9"
implementation "com.squareup.okhttp3:okhttp:4.9.0"
// 可选:如需后台上传能力,请按项目兼容版本引入 WorkManager
implementation "androidx.work:work-runtime:"
}
```
请访问 [Maven Central
版本页面](https://central.sonatype.com/artifact/cloud.flashcat/dd-sdk-android-core/versions)
获取最新版本号。
**Gson 与 OkHttp 必须由您的应用显式声明。** SDK 通过反射检测这两个依赖是否存在,但它们在 SDK 内部是 `compileOnly` 依赖、不会随 SDK 传递到您的工程。如果缺失,`Datadog.initialize(...)` 会抛出 `missing dependencies` 异常并导致应用启动崩溃(即使未开启混淆)。若您的应用已经引入了 Gson / OkHttp,可直接复用,无需重复添加。
WorkManager 也是 SDK 的 `compileOnly` 依赖,但不是强制依赖。缺少 WorkManager 时,SDK 会记录告警并禁用后台上传能力;前台批量上报仍可继续工作。若您希望 SDK 在应用进入后台后继续调度上传任务,请在应用中显式引入 `androidx.work:work-runtime`。
在 Flashduty 控制台的 [RUM 应用管理](https://console.flashcat.cloud/rum/apps)页面:
1. 创建或选择一个 Android 应用
2. 获取以下凭证信息:
* **Application ID** - 应用唯一标识符
* **Client Token** - 客户端访问令牌
在您的 `Application` 类的 `onCreate()` 方法中初始化 SDK:
```kotlin Application.kt theme={null}
import com.datadog.android.Datadog
import com.datadog.android.core.configuration.Configuration
import com.datadog.android.privacy.TrackingConsent
class SampleApplication : Application() {
override fun onCreate() {
super.onCreate()
val clientToken = ""
val environmentName = ""
val appVariantName = ""
val configuration = Configuration.Builder(
clientToken = clientToken,
env = environmentName,
variant = appVariantName
).build()
Datadog.initialize(this, configuration, TrackingConsent.GRANTED)
}
}
```
**参数说明:**
* `environmentName` - 环境名称(如 production、staging)
* `appVariantName` - 应用变体名称,用于区分不同构建版本的数据
* 更多配置选项请参阅 [高级配置](https://docs.flashduty.com/zh/flashduty/rum/android-advanced-configuration)
配置并启用 Android SDK 的 RUM 功能:
```kotlin Application.kt theme={null}
import com.datadog.android.rum.Rum
import com.datadog.android.rum.RumConfiguration
import com.datadog.android.rum.tracking.ActivityViewTrackingStrategy
val rumConfig = RumConfiguration.Builder(applicationId)
.trackUserInteractions()
.trackLongTasks(durationThreshold)
.useViewTrackingStrategy(ActivityViewTrackingStrategy(true))
.build()
Rum.enable(rumConfig)
```
SDK 将自动开始收集以下数据:
* 用户交互事件
* 长任务监控
* Activity 视图追踪
配置网络拦截器以追踪 HTTP 请求和响应:
### 开启分布式 Trace 追踪
如果只需要在 RUM 中查看请求 URL、方法、状态码和错误,配置 OkHttp
拦截器即可。若需要把移动端请求与后端 Trace 链路关联,还需要额外引入
Trace 模块并启用 `Trace.enable(...)`。
**添加 OkHttp 依赖:**
```groovy build.gradle theme={null}
dependencies {
implementation "cloud.flashcat:dd-sdk-android-okhttp:"
implementation "cloud.flashcat:dd-sdk-android-trace:"
}
```
`dd-sdk-android-okhttp` 负责把 OkHttp 请求记录为 RUM Resource;`dd-sdk-android-trace` 负责开启 Trace 功能、创建 span 并向一方域名请求注入 trace header。依赖使用 `cloud.flashcat`,代码 import 仍使用 `com.datadog.android.*` 包名。
**启用 Trace 功能:**
在 `Datadog.initialize(...)` 之后、发起网络请求之前启用 Trace:
```kotlin Application.kt theme={null}
import com.datadog.android.trace.DatadogTracing
import com.datadog.android.trace.GlobalDatadogTracer
import com.datadog.android.trace.Trace
import com.datadog.android.trace.TraceConfiguration
Trace.enable(
TraceConfiguration.Builder().build()
)
GlobalDatadogTracer.registerIfAbsent(
DatadogTracing.newTracerBuilder()
.withServiceName("")
.build()
)
```
`Trace.enable(...)` 是开启 Trace feature 的必要步骤。`GlobalDatadogTracer`
用于注册全局 tracer,方便 OkHttp、协程和手动 span 复用同一套 trace
配置;如果只使用 OkHttp 自动追踪,SDK 会在未注册全局 tracer
时创建本地 tracer,但建议显式注册以便指定 `service` 名称并降低排查成本。
**配置拦截器:**
```kotlin theme={null}
import com.datadog.android.okhttp.DatadogInterceptor
import com.datadog.android.trace.TracingHeaderType
val tracedHostsWithHeaderType = mapOf(
"example.com" to setOf(
TracingHeaderType.DATADOG, // datadog 协议
TracingHeaderType.TRACECONTEXT // w3c 标准协议
),
"api.example.com" to setOf(
TracingHeaderType.DATADOG,
TracingHeaderType.TRACECONTEXT
)
)
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(DatadogInterceptor.Builder(tracedHostsWithHeaderType).build())
.build()
```
使用 `DatadogInterceptor` 后,OkHttpClient
处理的一方域名请求会被自动记录为 RUM Resource,并在命中采样时注入
`x-datadog-*` 和 `traceparent` / `tracestate` 等 trace header,用于关联后端 Trace。
* host 只填写域名,不要包含 `http://`、`https://` 或路径;配置 `example.com` 会匹配 `api.example.com` 等子域名
* 只有在视图处于活动状态时发起的网络请求才会被追踪;要追踪应用在后台时的请求,请参阅 [追踪后台事件](#追踪后台事件)
* 如果使用多个拦截器,请将 `DatadogInterceptor` 添加为第一个拦截器;后续拦截器重新构造 `Request` 时需保留已有 headers
**追踪网络重定向或重试:**
要监控网络重定向或重试,可以将 `DatadogInterceptor` 用作网络拦截器:
```kotlin theme={null}
val okHttpClient = OkHttpClient.Builder()
.addNetworkInterceptor(DatadogInterceptor.Builder(tracedHostsWithHeaderType).build())
.build()
```
您还可以为 `OkHttpClient` 添加
`EventListener`,以自动追踪第三方提供商和网络请求的资源时序。
**过滤特定错误:**
要过滤 `DatadogInterceptor` 报告的特定错误,可以在 `RumConfiguration` 中配置自定义 `EventMapper`:
```kotlin theme={null}
val rumConfig = RumConfiguration.Builder(applicationId)
.setErrorEventMapper { errorEvent ->
if (errorEvent.shouldBeDiscarded()) {
null
} else {
errorEvent
}
}
.build()
```
## 高级配置
### 追踪后台事件
您可以追踪应用在后台运行时的事件(例如崩溃和网络请求):
```kotlin theme={null}
val rumConfig = RumConfiguration.Builder(applicationId)
.trackBackgroundEvents(true)
.build()
```
追踪后台事件可能会产生额外的会话,从而影响计费。如有疑问,请联系 Flashduty
支持团队。
### 离线数据处理
Android SDK 确保在用户设备离线时的数据可用性:
**数据持久化机制:** - 网络信号弱或设备电量过低时,事件以批次形式存储在本地 -
网络恢复后自动上传,确保不丢失数据 - 自动清理过旧数据,避免占用过多磁盘空间
即使用户在离线时使用应用,数据也会被保留并在网络恢复后上传,不会丢失任何监控数据。
### 追踪本地资源访问
您可以追踪 assets 和 raw 资源的访问情况:
```kotlin theme={null}
val inputStream = context.getAssetAsRumResource(fileName)
```
```kotlin theme={null}
val inputStream = context.getRawResAsRumResource(id)
```
## WebView 集成
如果您的 Android 应用中包含 WebView,可以启用 WebView 追踪来监控 Web 内容的性能和错误。
```groovy build.gradle theme={null}
dependencies {
implementation "cloud.flashcat:dd-sdk-android-webview:"
}
```
在您的 Activity 或 Fragment 中启用 WebView 追踪:
```kotlin theme={null}
import com.datadog.android.webview.WebViewTracking
// 为指定的 WebView 启用追踪
WebViewTracking.enable(webView, listOf("example.com", "*.example.com"))
```
**参数说明:**
* `webView` - 需要追踪的 WebView 实例
* `allowedHosts` - 允许追踪的域名列表,支持通配符(如 `*.example.com`)
WebView 中的 Web 页面现在可以与原生应用的 RUM 数据关联起来。
## 验证接入
接入完成后,验证集成是否成功:
登录 Flashduty 控制台,进入对应的 RUM 应用,查看是否有数据上报。
在应用中执行以下操作验证数据采集: - 打开应用的不同页面,验证页面浏览事件 -
执行用户操作(点击、滑动等),验证交互事件 - 触发网络请求,验证资源加载事件
在 Logcat 中查看是否有向数据上报端点的网络请求。
如果看到数据上报请求且控制台中有数据显示,说明集成成功!
## 混淆配置
如果您的应用启用了代码混淆(ProGuard/R8),请在 `proguard-rules.pro` 文件中添加以下规则:
```proguard proguard-rules.pro theme={null}
# Flashduty SDK (兼容 Datadog 协议)
-keep class com.datadog.android.** { *; }
-dontwarn com.datadog.android.**
```
自 **0.4.1** 起,SDK 已通过 AAR consumer rules 内置自身所需的混淆规则,包括保留 `SourceFile`、`LineNumberTable`、SDK shaded 依赖,以及初始化时通过反射检测的 Gson / OkHttp 关键类。您**无需**为 SDK 手动添加 Gson / OkHttp keep 规则。上述规则仅用于保留 SDK 公开类。如果您自己使用 Gson 序列化业务模型,仍需按 Gson 惯例为**您自己的 model 类**添加 keep 规则。
## 下一步
深入配置 SDK 的高级功能,如自定义采样、用户标识、全局上下文等
了解 SDK 收集的数据类型和数据结构
查看和分析应用的性能、错误和用户行为数据
配置崩溃报告和异常追踪功能
# Electron SDK 高级配置
Source: https://docs.flashduty.com/zh/rum/sdk/electron/advanced-config
配置 Electron RUM SDK 的上报地址、批次、用户身份、错误上报和其他进阶选项
本文介绍主进程 `@flashcatcloud/electron-sdk` 的可选配置和公开 API。渲染进程使用 Browser SDK,其通用配置见 [Web SDK 高级配置](/zh/rum/sdk/web/advanced-config)。
## 初始化参数
```ts main.ts theme={null}
import { app } from 'electron';
import { init } from '@flashcatcloud/electron-sdk';
const initialized = await init({
applicationId: '',
clientToken: '',
service: 'my-electron-app',
env: 'production',
version: app.getVersion(),
});
if (!initialized) {
console.error('[Flashduty RUM] SDK initialization failed');
}
```
| 参数 | 类型 | 必填 | 默认值 | 说明 |
| ----------------------------- | ---------------------------------------- | -- | ------------------------ | --------------------------------- |
| `applicationId` | `string` | 是 | — | RUM 应用 ID |
| `clientToken` | `string` | 是 | — | 客户端 Token |
| `service` | `string` | 是 | — | 服务名称;上传 sourcemap 时需要使用相同的值 |
| `site` | `string` | 否 | `browser.flashcat.cloud` | 普通 RUM 事件的上报域名,只填写 host,不包含协议和路径 |
| `proxy` | `string` | 否 | — | 普通 RUM 事件的自定义转发地址 |
| `env` | `string` | 否 | — | 环境标识。当前主进程 RUM 事件不带该字段;渲染进程需要单独配置 |
| `version` | `string` | 否 | — | 应用版本;上传 sourcemap 时需要使用相同的值 |
| `telemetrySampleRate` | `number` | 否 | `20` | SDK 自身遥测采样率,范围为 0–100;设为 `0` 可关闭 |
| `batchSize` | `'SMALL' \| 'MEDIUM' \| 'LARGE'` | 否 | `MEDIUM` | 普通 RUM 事件的单批大小 |
| `uploadFrequency` | `'RARE' \| 'NORMAL' \| 'FREQUENT'` | 否 | `NORMAL` | 普通 RUM 事件的上报间隔 |
| `defaultPrivacyLevel` | `'mask' \| 'allow' \| 'mask-user-input'` | 否 | `mask` | 渲染进程没有单独配置时使用的回放隐私级别 |
| `allowedWebViewHosts` | `string[]` | 否 | `[]` | 允许通过桥接上报的额外 host;当前窗口自身无需配置 |
| `correctPrewarmedViewTimings` | `boolean` | 否 | `true` | 校正预创建隐藏窗口的 FCP / LCP |
| `normalizeStackPaths` | `boolean` | 否 | `true` | 将应用目录中的错误栈路径归一化为稳定的 `app:///` 路径 |
| `normalizeStackPath` | `(path: string) => string \| undefined` | 否 | — | 自定义单个栈帧的路径映射 |
`init()` 返回 `false` 表示配置校验失败。SDK 会在主进程控制台输出具体原因,并且不会开始采集,但不会阻止应用继续启动。
## 自定义上报地址
默认情况下,普通 RUM 事件由主进程上报到 Flashduty SaaS,无需配置 `site` 或 `proxy`。
| 场景 | 配置方式 |
| ---------------------------------- | ------------------------- |
| Flashduty SaaS | 无需配置 |
| 私有化数据接收端使用 HTTPS,路径为 `/api/v2/rum` | 在主进程配置 `site` |
| 需要自定义路径、统一网关或转发服务 | 在主进程配置 `proxy` |
| 私有化部署并开启会话回放 | 除主进程配置外,还要在渲染进程配置 `proxy` |
### 使用私有化接收域名
如果数据接收端支持 HTTPS,并且接收路径为 `/api/v2/rum`,请将域名填入 `site`。不要包含 `https://` 或路径:
```ts main.ts theme={null}
await init({
// 其余配置
site: 'rum.example.internal',
});
```
SDK 会向 `https://rum.example.internal/api/v2/rum` 上报普通 RUM 事件。
### 使用自定义转发地址
以下场景请使用 `proxy`:
* 数据接收端只提供 HTTP
* 上报路径不是 `/api/v2/rum`
* 客户端需要通过统一网关访问数据接收端
```ts main.ts theme={null}
await init({
// 其余配置
proxy: 'https://rum-gateway.example.internal/forward',
});
```
这里的 `proxy` 是由你提供的 **RUM 转发地址**,不是操作系统或 Electron 的网络代理设置。主进程会在请求中附加目标路径信息;转发服务需要保留请求体和 `DD-API-KEY` 请求头,并将请求发送到 Flashduty 数据接收端。
设置 `proxy` 后,主进程不再使用 `site` 生成上报地址。
### 为会话回放配置私有化地址
普通 RUM 事件通过主进程上报,但会话回放由渲染进程直接上传。因此,主进程的 `site` 或 `proxy` 不会自动应用到回放。
私有化部署开启回放时,请在渲染进程配置 Browser SDK 的 `proxy`:
```ts renderer.ts theme={null}
flashcatRum.init({
applicationId: '',
clientToken: '',
service: 'my-electron-app',
proxy: 'https://rum-gateway.example.internal/forward',
sessionReplaySampleRate: 100,
sessionReplayDirectUpload: true,
});
```
同时将该地址加入页面 CSP 的 `connect-src`。
## 上报批次与频率
普通 RUM 事件会先写入应用的 `userData` 目录,再按批次上传。上传成功后,SDK 才会删除对应的批次文件。
| `batchSize` | 单批大小 |
| ----------- | ------- |
| `SMALL` | 16 KiB |
| `MEDIUM` | 512 KiB |
| `LARGE` | 4 MiB |
| `uploadFrequency` | 上报间隔 |
| ----------------- | ---- |
| `RARE` | 30 秒 |
| `NORMAL` | 10 秒 |
| `FREQUENT` | 5 秒 |
接入调试时,可以使用 `batchSize: 'SMALL'` 和 `uploadFrequency: 'FREQUENT'` 更快看到数据。正常运行时建议保留默认值。
这套落盘与重试机制只覆盖普通 RUM 事件。会话回放由渲染进程直接上传,不使用主进程的磁盘缓冲。
## 采集第三方页面
当前窗口加载的页面始终可以使用桥接,无需配置 `allowedWebViewHosts`。只有当你需要采集 `` 或 `BrowserView` 中加载的第三方页面时,才添加额外 host:
```ts main.ts theme={null}
await init({
// 其余配置
allowedWebViewHosts: ['partner.example.com'],
});
```
匹配规则包含子域名。例如配置 `example.com` 后,`app.example.com` 也可以使用桥接。
## 关联登录用户
用户登录后,在主进程调用 `setUser()`。主进程事件和通过桥接上报的渲染进程事件都会带上相同的用户身份。
```ts main.ts theme={null}
import { clearUser, getUser, setUser } from '@flashcatcloud/electron-sdk';
setUser({
id: 'user-123',
name: 'Alice',
email: 'alice@example.com',
});
console.log(getUser());
// 用户退出登录时
clearUser();
```
| 字段 | 必填 | 说明 |
| ------- | -- | ------ |
| `id` | 是 | 用户唯一标识 |
| `name` | 否 | 用户名称 |
| `email` | 否 | 用户邮箱 |
开启会话回放时,请在同一套登录和退出流程中同步调用渲染进程的 `flashcatRum.setUser()` 与 `flashcatRum.clearUser()`,因为回放分段不会经过主进程。
## 手动上报错误
主进程中被 `try/catch` 捕获的异常不会作为未处理异常自动上报。你可以调用 `addError()` 记录它:
```ts main.ts theme={null}
import { addError } from '@flashcatcloud/electron-sdk';
try {
await syncWorkspace();
} catch (error) {
addError(error, {
context: {
component: 'sync',
workspaceId: 'ws-1001',
},
});
}
```
手动上报的错误会标记为已处理错误。`context` 中的属性可用于筛选和定位业务场景。
## 结束当前会话
用户退出登录或需要重新开始会话时,可以调用 `stopSession()`:
```ts main.ts theme={null}
import { stopSession } from '@flashcatcloud/electron-sdk';
stopSession();
```
当前会话会立即结束。下一次有效的界面输入会创建新会话。
## 预创建窗口的性能指标
Electron 应用可能先创建隐藏的 `BrowserWindow`,完成页面加载后再显示。SDK 默认会将这类窗口的 FCP 和 LCP 校正到窗口首次可见的时间,避免把预热等待时间计入页面性能。
如果你希望保留页面原始的 Paint Timing 数值,可以关闭校正:
```ts main.ts theme={null}
await init({
// 其余配置
correctPrewarmedViewTimings: false,
});
```
该能力只覆盖 `BrowserWindow`。`WebContentsView` 和 `` 的指标不会校正。
## 自定义错误栈路径
SDK 默认把应用目录中的错误栈路径改写为 `app:///<相对路径>`,让同一份 sourcemap 可以匹配不同机器上的安装路径。大多数项目无需修改。
如果构建产物的目录结构与应用目录不一致,可以通过 `normalizeStackPath` 自定义映射:
```ts main.ts theme={null}
await init({
// 其余配置
normalizeStackPath: (absolutePath) => {
const normalized = absolutePath.replace(/\\/g, '/');
const match = /\/public(\/dist\/.+)$/.exec(normalized);
return match ? match[1] : undefined;
},
});
```
返回 `undefined` 时,SDK 会继续使用默认归一化逻辑。上传方法见 [Electron 错误还原](/zh/rum/sdk/electron/error-symbolication)。
## 相关页面
完成主进程与渲染进程接入。
上传 JavaScript sourcemap 和原生崩溃符号。
查看 SDK 采集的数据类型与上报行为。
排查桥接、回放和数据上报问题。
# Electron SDK 兼容性
Source: https://docs.flashduty.com/zh/rum/sdk/electron/compatible
查看 Electron RUM SDK 支持的版本、操作系统、打包工具和当前限制
接入前,请确认你的 Electron 版本和构建方式在支持范围内。
## 支持范围
| 项目 | 支持情况 |
| --------- | --------------------------------------------- |
| Electron | 39 或更高版本 |
| 操作系统 | macOS、Windows、Linux |
| 主进程 SDK | `@flashcatcloud/electron-sdk` |
| 渲染进程 SDK | `@flashcatcloud/browser-rum` 0.0.7 或更高版本 |
| 模块格式 | CommonJS、ESM |
| 普通 RUM 上报 | `POST https:///api/v2/rum`,也可以配置自定义转发地址 |
## 打包工具
| 构建方式 | 支持情况 | 接入方式 |
| ----------------------------------- | ----- | ------------------------------------------------------------------ |
| 主进程不打包 | 支持 | 在第一条 import 引入 `@flashcatcloud/electron-sdk/instrument` |
| Vite / electron-vite / Forge + Vite | 支持 | 使用 `@flashcatcloud/electron-sdk/vite-plugin` |
| Webpack / Forge + Webpack | 支持 | 使用 `@flashcatcloud/electron-sdk/webpack-plugin` |
| esbuild | 支持 | 使用 `@flashcatcloud/electron-sdk/esbuild-plugin` |
| 其他打包工具 | 需自行适配 | 保证 instrument 先于 Electron 加载,并将 `dd-trace` 和 Electron SDK 保留为运行时依赖 |
主进程打包时,请使用对应插件。插件会处理插桩的执行顺序、运行时依赖以及桥接 preload。
## 渲染进程页面加载方式
当前窗口加载的页面无需配置 host 白名单。
| 加载方式 | 支持情况 | 说明 |
| ------------------------------------ | ---- | ----------------------------------- |
| `loadURL('http://localhost:')` | 支持 | 适用于本地开发服务 |
| `loadURL('https://')` | 支持 | 当前页面自动允许使用桥接 |
| 自定义协议,例如 `app://` | 支持 | 当前页面自动允许使用桥接 |
| `loadFile()` / `file://` | 支持 | 无需额外配置 |
| `` / `BrowserView` 中的第三方页面 | 需配置 | 将第三方 host 添加到 `allowedWebViewHosts` |
## 功能支持
| 能力 | 支持情况 | 说明 |
| -------------------- | ---- | ------------------------------------------------------- |
| 主进程会话与 view | 支持 | SDK 为主进程维护会话和固定 view |
| 主进程 JavaScript 错误 | 支持 | 自动采集未捕获异常和未处理 Promise 拒绝 |
| 原生崩溃 | 支持 | 崩溃后生成 minidump,并在下次启动时上报 |
| 渲染进程终止 | 支持 | 采集 `render-process-gone` 和 `child-process-gone` |
| 主进程网络请求 | 支持 | 采集 `http`、`https`、`fetch` 和 `net.fetch` |
| 渲染进程页面体验 | 支持 | 与 Web SDK 一致,包含 view、action、resource、error 和 Web Vitals |
| 会话回放 | 支持 | 需要渲染进程直传并允许相应 CSP |
| JavaScript sourcemap | 支持 | 主进程和渲染进程均支持 |
| 原生崩溃符号还原 | 支持 | 需要上传匹配的 Breakpad 符号文件 |
## 当前限制
| 限制 | 影响 |
| ---------------------------- | ----------------------------------------------------- |
| 会话回放不经过主进程 | 回放需要在渲染进程配置 `sessionReplayDirectUpload`、CSP 和私有化转发地址 |
| 不提供完整 APM | 当前只将主进程 HTTP span 转换为 RUM resource;IPC 和子进程 span 不会上报 |
| 不转发 Logs | 渲染进程通过桥接发送的 log 事件不会作为 RUM 数据上报 |
| 主进程没有 Web Vitals | LCP、INP、CLS、long task 和用户操作来自渲染进程 |
| 主进程 RUM 事件不带 `env` | 渲染进程事件仍保留 `flashcatRum.init()` 中的 `env` |
| 预创建窗口指标校正仅覆盖 `BrowserWindow` | `WebContentsView` 和 `` 不会校正 FCP / LCP |
| 原生崩溃需要符号文件 | 未上传符号时,崩溃事件仍会上报,但调用栈保持原始地址 |
详细排查方法见 [Electron SDK 问题排查](/zh/rum/sdk/electron/faq)。
## 相关页面
完成主进程与渲染进程接入。
配置自定义上报地址与公开 API。
了解每个进程采集的数据类型。
还原 JavaScript 和原生崩溃调用栈。
# Electron SDK 数据收集
Source: https://docs.flashduty.com/zh/rum/sdk/electron/data-collection
了解 Electron RUM SDK 在主进程和渲染进程中采集的数据、关联方式与上报行为
Electron SDK 将主进程和渲染进程的数据关联到同一条会话,帮助你同时分析桌面应用运行状态和页面体验。
## 采集概览
| 数据 | 主进程 | 渲染进程 |
| ------------- | ---------------------------------- | ----------------------- |
| 会话 | 负责创建、续期和结束 | 使用主进程会话 ID |
| view | 每个主进程实例维护一个固定 view | 记录页面加载和路由切换 |
| 用户操作 | 不采集 | 点击、输入和自定义 action |
| 网络请求 | `http`、`https`、`fetch`、`net.fetch` | `fetch`、XHR 和静态资源 |
| JavaScript 错误 | 未捕获异常、Promise 拒绝、手动错误 | 页面错误和手动错误 |
| 原生崩溃 | 主进程崩溃和进程终止 | 由主进程监听渲染进程终止 |
| 性能指标 | 不产生 Web Vitals | LCP、INP、CLS、long task 等 |
| 会话回放 | 不录制 | 在渲染进程录制并直接上传 |
渲染进程的页面数据由 `@flashcatcloud/browser-rum` 采集,支持范围与 [Web SDK 数据收集](/zh/rum/sdk/web/data-collection)一致。
## 区分主进程和渲染进程
两类事件使用不同的来源字段:
| 事件来源 | `source` | `container.source` | `view.url` |
| ---- | ---------- | ------------------ | ------------------------- |
| 主进程 | `electron` | 无 | `electron://main-process` |
| 渲染进程 | `browser` | `electron` | 当前页面 URL |
要筛选一个 Electron 应用产生的全部事件,请使用:
```text theme={null}
source:electron OR container.source:electron
```
只使用 `source:electron` 会遗漏渲染进程数据。
如果渲染进程事件没有 `container.source: electron`,说明事件没有经过主进程桥接。请参阅[为什么只有主进程数据](/zh/rum/sdk/electron/faq#为什么只有主进程数据)。
在控制台中,错误详情和会话事件详情的属性面板会在「Other」属性组中额外展示一个虚拟的 `process` 属性,取值为「主进程」或「渲染进程」,用于直接区分事件来自哪个进程;会话事件列表中,主进程事件还会带有「主进程」标记。
## 会话
主进程负责 Electron 应用的会话生命周期:
| 规则 | 行为 |
| ----- | -------------------------- |
| 无操作超时 | 连续 15 分钟没有有效界面输入后结束会话 |
| 最大时长 | 单个会话最长 4 小时 |
| 活跃信号 | 鼠标按下、滚轮、按键等 Electron 输入事件 |
| 应用重启 | 未过期的会话可以继续使用 |
| 会话续期 | 会话结束后,下一次有效输入会创建新会话和新 view |
纯主进程后台任务不会延长会话,也不会自动创建新会话。
## 用户身份
主进程 SDK 会为应用生成稳定的匿名设备标识。调用 `setUser()` 后,主进程事件和通过桥接上报的渲染进程事件都会带上登录用户信息。
| 状态 | 后续事件中的用户信息 |
| --------------------------------- | ----------------- |
| 未调用 `setUser()` | 只包含匿名设备标识 |
| 调用 `setUser({ id, name, email })` | 同时包含匿名设备标识和登录用户信息 |
| 调用 `clearUser()` | 移除登录用户信息,保留匿名设备标识 |
会话回放由渲染进程直接上传。开启回放时,请在渲染进程同步调用 `flashcatRum.setUser()` 和 `flashcatRum.clearUser()`。
API 用法见[关联登录用户](/zh/rum/sdk/electron/advanced-config#关联登录用户)。
## 主进程 view
主进程没有页面路由。SDK 为每个主进程实例维护一个固定 view,并将主进程的错误和网络请求关联到该 view。
该 view 的主要标识为:
| 字段 | 值或含义 |
| ----------------- | ------------------------- |
| `view.url` | `electron://main-process` |
| `view.name` | `main process` |
| `view.time_spent` | 主进程 view 已持续的时间 |
| `view.is_active` | 当前会话是否仍然活跃 |
渲染进程仍按 Web SDK 规则创建自己的页面 view。主进程 view 不包含渲染进程页面的 Web Vitals 和用户操作计数。
## 错误与崩溃
### JavaScript 错误
| 来源 | 采集方式 |
| ------------------ | ------------------------- |
| 主进程未捕获异常 | 自动采集 `uncaughtException` |
| 主进程未处理 Promise 拒绝 | 自动采集 `unhandledRejection` |
| 主进程已捕获异常 | 调用 `addError()` 手动上报 |
| 渲染进程 JavaScript 错误 | 由 Browser SDK 自动采集 |
主进程和渲染进程的错误栈都会归一化为稳定路径,可以使用 sourcemap 还原。操作方法见 [Electron 错误还原](/zh/rum/sdk/electron/error-symbolication#还原-javascript-错误)。
### 原生崩溃
Electron 发生原生崩溃时,会在本地生成 minidump。进程已经终止,无法立即上报,因此 SDK 会在应用下一次启动时读取并上报崩溃事件。
崩溃事件包含:
* 崩溃类型和进程信息
* 崩溃线程及其他线程的调用栈
* 加载的原生模块
* 操作系统和 CPU 架构
未上传符号文件时,原生调用栈会显示模块名和地址。上传匹配的 Breakpad 符号后,Flashduty 可以还原函数名、文件名和行号。
### 进程终止
SDK 还会监听渲染进程和 Electron 子进程终止,包括被系统结束、启动失败或沙箱终止等不会产生 minidump 的情况。
这类事件会记录进程类型、退出原因、退出码和页面 URL,但没有调用栈。
## 主进程网络请求
SDK 自动采集主进程发起的 `http`、`https`、`fetch` 和 `net.fetch` 请求,并将它们记录为 RUM resource。
主要字段包括:
* 请求 URL 和方法
* HTTP 状态码
* 请求耗时
* Trace ID 和 Span ID
主进程 resource 的 `resource.type` 为 `native`,可以与渲染进程的 `fetch` 和 `xhr` 区分。
当前不提供完整 APM。只有 HTTP span 会转换为 RUM resource;IPC 和子进程命令 span 不会上报。
## 上报与重试
普通 RUM 事件和会话回放使用不同的上报方式:
| 数据 | 上报进程 | 缓冲与重试 |
| ------------- | --------- | ----------------------------- |
| 主进程事件 | 主进程 | 写入磁盘,上传成功后删除;应用重启后可以继续发送 |
| 渲染进程普通 RUM 事件 | 通过桥接交给主进程 | 与主进程事件使用相同的磁盘缓冲 |
| 会话回放分段 | 渲染进程直接上传 | 使用 Browser SDK 的内存重试,不写入主进程磁盘 |
因此,主进程的 `site`、`proxy`、`batchSize` 和 `uploadFrequency` 不会改变会话回放的上传行为。私有化回放地址需要在渲染进程单独配置。
## 相关页面
完成主进程与渲染进程接入。
配置上报地址、用户身份和公开 API。
还原 JavaScript 和原生崩溃调用栈。
排查数据缺失、桥接和回放问题。
# Electron 错误还原
Source: https://docs.flashduty.com/zh/rum/sdk/electron/error-symbolication
上传 Electron 应用的 JavaScript sourcemap 和原生崩溃符号,还原生产环境调用栈
Electron 应用包含 JavaScript 错误和原生崩溃,两者使用不同的还原方式:
| 错误类型 | 原始调用栈 | 需要上传 |
| ---------------------- | ----------- | ------------------ |
| 主进程和渲染进程 JavaScript 错误 | 压缩后的文件名和行列号 | 构建生成的 sourcemap |
| Electron 或原生模块崩溃 | 模块名和内存地址 | Breakpad `.sym` 文件 |
## 还原 JavaScript 错误
SDK 默认将应用目录中的栈帧转换为稳定的 `app:///<相对路径>`。无论用户把应用安装到哪里,同一份构建都会得到相同的路径。
例如:
```text theme={null}
Error: something went wrong
at handleClick @ app:///dist/renderer/index.js:97:15
```
上传时只使用 URL 的 path 部分。上例对应的目录前缀是 `/dist/renderer`。
### 1. 统一 service 和 version
Flashduty 使用以下信息匹配 sourcemap:
* 事件中的 `service`
* 事件中的 `version`
* 栈帧中的压缩文件路径
建议让主进程和渲染进程使用相同的版本变量:
```ts main.ts theme={null}
await init({
// 其余配置
service: 'my-electron-app',
version: '1.4.2',
});
```
```ts renderer.ts theme={null}
flashcatRum.init({
// 其余配置
service: 'my-electron-app',
version: '1.4.2',
});
```
主进程的 `version` 不会自动写入渲染进程事件,因此两侧都需要配置。
### 2. 生成 sourcemap
为主进程和渲染进程构建开启 sourcemap:
```ts Vite theme={null}
export default defineConfig({
build: { sourcemap: true },
});
```
```js Webpack theme={null}
module.exports = {
mode: 'production',
devtool: 'source-map',
};
```
```ts esbuild theme={null}
await esbuild.build({
sourcemap: true,
});
```
### 3. 上传主进程和渲染进程产物
安装 [Flashduty CLI](https://github.com/flashcatcloud/flashcat-cli),然后分别上传两个进程的 sourcemap:
```bash theme={null}
npm install --global @flashcatcloud/flashcat-cli
```
```bash theme={null}
# 主进程栈:app:///dist/main/index.js
flashcat-cli sourcemaps upload ./out/main \
--service my-electron-app \
--release-version 1.4.2 \
--minified-path-prefix /dist/main \
--api-key
# 渲染进程栈:app:///dist/renderer/index.js
flashcat-cli sourcemaps upload ./out/renderer \
--service my-electron-app \
--release-version 1.4.2 \
--minified-path-prefix /dist/renderer \
--api-key
```
`--minified-path-prefix` 应与错误详情中栈帧的目录一致。不要在前缀中包含 `app:///`。
不要将 `.map` 文件打入最终分发的应用包。完成上传后,请在生成安装包前从分发产物中排除它们。
### 自定义路径映射
大多数项目可以直接使用默认的 `app:///` 路径。只有构建目录无法按应用根目录表达时,才配置 `normalizeStackPath`:
```ts main.ts theme={null}
await init({
// 其余配置
normalizeStackPath: (absolutePath) => {
const normalized = absolutePath.replace(/\\/g, '/');
const match = /\/public(\/dist\/.+)$/.exec(normalized);
return match ? match[1] : undefined;
},
});
```
该回调同时应用于主进程和通过桥接上报的渲染进程栈。返回 `undefined` 时,SDK 会继续使用默认规则。
## 还原原生崩溃
原生崩溃来自 Electron `crashReporter` 生成的 minidump。未上传符号时,调用栈会显示模块和地址:
```text theme={null}
0 Electron Framework 0x000000010ab12345
1 libsystem_kernel 0x00007ff81a2b3c4d
```
上传匹配的 Breakpad 符号后,Flashduty 可以还原函数名、文件名和行号。
### 1. 准备符号文件
从 [Electron releases](https://github.com/electron/electron/releases) 下载与你实际发布的 Electron **版本、操作系统和 CPU 架构**完全一致的符号包:
```text theme={null}
electron-v---symbols.zip
```
真实崩溃中的大多数栈帧通常位于 Electron 自带模块中,因此建议优先上传官方符号包。
如果应用包含自己的原生模块或 `.node` 插件,请使用 [dump\_syms](https://github.com/mozilla/dump_syms) 为这些模块生成 `.sym` 文件。
### 2. 上传符号
将 `.sym` 文件放在同一个目录中,然后执行:
```bash theme={null}
flashcat-cli electron-symbols upload ./breakpad_symbols \
--service my-electron-app \
--release-version 1.4.2
```
使用 `--dry-run` 可以先查看将要上传的文件。
原生符号按模块 ID 匹配。命令中的 `service` 和 `release-version` 用于标记上传批次,方便查询,不参与符号匹配。这一点与 JavaScript sourcemap 不同。
### 3. 随版本发布符号
每次升级 Electron 或重新构建原生模块后,模块 ID 都可能变化。请为实际发布的每个操作系统和 CPU 架构上传对应符号。
未上传符号不会阻止崩溃事件上报。你可以先收到地址形式的崩溃栈,再补传符号;历史崩溃会在查看时重新还原。
## 验证错误还原
### JavaScript 错误
1. 在测试版本中触发一个包含稳定调用栈的错误
2. 在错误详情中确认事件的 `service` 和 `version`
3. 检查栈帧路径与 `--minified-path-prefix` 是否对应
4. 确认详情页显示原始文件名、函数名和源码位置
### 原生崩溃
1. 使用与发布版本相同的 Electron 构建触发测试崩溃
2. 重新启动应用,让 SDK 上报 minidump
3. 在崩溃详情中确认 Electron 模块帧已显示函数名和行号
如果上传成功但调用栈仍未还原,请参阅 [Electron SDK 问题排查](/zh/rum/sdk/electron/faq#为什么-sourcemap-上传成功但错误栈没有还原)。
## 相关页面
配置版本、路径映射和其他进阶选项。
了解 JavaScript 错误与原生崩溃的采集方式。
# Electron SDK 问题排查
Source: https://docs.flashduty.com/zh/rum/sdk/electron/faq
排查 Electron RUM SDK 的数据缺失、进程桥接、会话回放和错误还原问题
本页按照你在应用或 Flashduty 控制台中看到的现象,提供对应的检查方法。
请按以下顺序检查:
1. 确认主进程 `init()` 返回 `true`,并查看主进程控制台是否有配置错误
2. 确认 `applicationId`、`clientToken` 和 `service` 为非空字符串
3. 确认应用可以访问 `https://browser.flashcat.cloud/api/v2/rum` 或你配置的私有化地址
4. 等待一个上报周期;默认每 10 秒上报一批普通 RUM 事件
5. 在查看器中使用 `source:electron OR container.source:electron` 筛选
接入调试时,可以配置 `batchSize: 'SMALL'` 和 `uploadFrequency: 'FREQUENT'` 缩短等待时间。
如果能看到 `source: electron`,但看不到渲染进程的 view、action 或 resource,请检查:
1. 渲染进程是否安装并初始化了 `@flashcatcloud/browser-rum`
2. 主进程是否在创建 `BrowserWindow` 之前完成 `init()`
3. 主进程不打包时,`instrument` 是否位于 `electron` import 之前
4. 主进程打包时,是否使用了对应的 Vite、Webpack 或 esbuild 插件
渲染进程接入成功后,其事件会带有 `container.source: electron`。
缺少 `container.source` 表示 Browser SDK 没有通过 Electron 桥接上报,而是作为普通 Web 页面直接连接上报地址。
常见原因包括:
* 主进程没有执行 instrumentation
* 打包配置没有保留 Electron SDK 或其 preload
* SDK 初始化失败
请先按[接入指南 · 配置主进程入口](/zh/rum/sdk/electron/sdk-integration#接入步骤)检查构建方式,再重新启动应用验证。
当前窗口本身不需要配置 `allowedWebViewHosts`。该参数只用于 `` 或 `BrowserView` 中加载的第三方页面。
请依次检查以下条件:
1. `@flashcatcloud/browser-rum` 版本为 0.0.7 或更高
2. 渲染进程同时设置了 `sessionReplaySampleRate` 和 `sessionReplayDirectUpload: true`
3. `sessionReplaySampleRate` 大于 0,并且当前会话被采样
4. 页面 CSP 允许 `worker-src blob:`
5. 页面 CSP 的 `connect-src` 包含实际使用的回放上报地址
6. 私有化部署已在渲染进程配置 `proxy`
在渲染进程 DevTools 中查看 Console 和 Network 面板。CSP 阻止 Worker 时,Console 会显示相关错误;上报地址错误时,Network 面板中的 replay 请求会失败。
会话回放分段由渲染进程直接上传,不使用主进程的磁盘缓冲。
设备真正离线时,Browser SDK 会将分段放入内存队列,并在网络恢复后尝试补发。但如果设备显示在线,而请求因 DNS、代理、网关、安全软件或数据接收端故障而失败,失败分段不会进入重试队列。后续分段可能缺少恢复画面所需的完整快照,从而表现为缺失或花屏。
请检查:
* 上报域名是否加入防火墙和终端安全软件的允许列表
* DNS 和代理配置是否可以稳定访问上报地址
* 页面 CSP 是否允许实际的回放地址
* 私有化转发服务是否持续可用
已经丢失的分段无法从主进程磁盘恢复。
普通 RUM 事件和会话回放使用两条上报链路:
* 普通事件通过桥接交给主进程,使用主进程的 `site` 或 `proxy`
* 回放分段由渲染进程直接上传,使用渲染进程 Browser SDK 的 `proxy`
因此,只配置主进程不会改变回放地址。请在 `flashcatRum.init()` 中配置渲染进程 `proxy`,并将该地址加入 CSP 的 `connect-src`。
完整示例见[自定义上报地址](/zh/rum/sdk/electron/advanced-config#自定义上报地址)。
Flashduty 使用 `service`、`version` 和压缩文件路径匹配 sourcemap。请检查:
1. `--service` 是否与产生错误的进程配置一致
2. `--release-version` 是否与产生错误的进程 `version` 一致
3. 渲染进程是否也配置了 `version`;主进程的版本不会自动应用到渲染进程
4. `--minified-path-prefix` 是否与错误详情中栈帧的目录一致
5. 主进程和渲染进程产物是否分别上传
如果栈帧是 `app:///dist/renderer/index.js`,前缀应填写 `/dist/renderer`,不要包含 `app:///`。
完整步骤见 [Electron 错误还原](/zh/rum/sdk/electron/error-symbolication#还原-javascript-错误)。
原生 minidump 不使用 JavaScript sourcemap。你需要上传与应用实际发布版本、操作系统和 CPU 架构匹配的 Breakpad 符号文件。
建议先上传对应 Electron 版本的官方符号包;如果应用包含自己的原生模块或 `.node` 插件,也需要为这些模块生成并上传 `.sym` 文件。
上传后,历史崩溃也可以在查看时完成还原。操作方法见[还原原生崩溃](/zh/rum/sdk/electron/error-symbolication#还原原生崩溃)。
## 仍然无法解决
联系支持人员时,请提供:
* Electron、`@flashcatcloud/electron-sdk` 和 `@flashcatcloud/browser-rum` 版本
* 使用的打包工具和模块格式
* 主进程初始化配置(移除 Client Token)
* 主进程与渲染进程 Console 错误
* 失败请求的 URL、状态码和错误类型
请不要发送 Client Token、服务端密钥或包含用户隐私的数据。
# Electron SDK 接入指南
Source: https://docs.flashduty.com/zh/rum/sdk/electron/sdk-integration
在 Electron 应用中接入 Flashduty RUM,采集主进程和渲染进程的性能、错误与用户操作数据
Electron 应用包含主进程和渲染进程。完成两侧接入后,你可以在同一条 RUM 会话中查看桌面应用的运行状态和页面体验。
| 进程 | SDK | 主要采集内容 |
| ---- | ----------------------------- | --------------------------------------- |
| 主进程 | `@flashcatcloud/electron-sdk` | 会话、主进程错误、原生崩溃、主进程网络请求 |
| 渲染进程 | `@flashcatcloud/browser-rum` | 页面访问、用户操作、前端资源、JavaScript 错误、Web Vitals |
普通渲染进程事件会自动转发到主进程,由主进程统一上报。你不需要编写额外的 IPC 转发代码。
## 前提条件
接入前,请确认:
* Electron 版本为 39 或更高
* 已在 Flashduty 控制台的 [RUM 应用管理](https://console.flashcat.cloud/rum/apps) 页面创建 Electron 应用,并获取 **Application ID** 和 **Client Token**
* 应用运行环境可以访问 `https://browser.flashcat.cloud/api/v2/rum`;私有化部署请准备自己的上报地址
## 接入步骤
在项目中安装主进程 SDK 和 Browser SDK:
```bash theme={null}
npm install @flashcatcloud/electron-sdk @flashcatcloud/browser-rum@^0.0.7
```
`@flashcatcloud/browser-rum` 需要使用 0.0.7 或更高版本,才能在 Electron 中启用会话回放。
Electron SDK 需要在 Electron 模块加载前完成插桩。请根据主进程是否打包选择一种配置方式。
将 `instrument` 放在主进程入口的第一条 import:
```ts main.ts theme={null}
import '@flashcatcloud/electron-sdk/instrument';
import { app, BrowserWindow } from 'electron';
```
如果项目使用 import 排序规则,请确保该 import 不会被移动到 `electron` 之后。
在主进程的 Vite 配置中添加插件。electron-vite 项目应添加到 `main` 配置,而不是 `renderer` 配置。
```ts vite.config.ts theme={null}
import { defineConfig } from 'vite';
import { datadogVitePlugin } from '@flashcatcloud/electron-sdk/vite-plugin';
export default defineConfig({
plugins: [datadogVitePlugin()],
});
```
在主进程的 Webpack 配置中添加插件:
```js webpack.main.config.js theme={null}
const { DatadogWebpackPlugin } = require('@flashcatcloud/electron-sdk/webpack-plugin');
module.exports = {
plugins: [new DatadogWebpackPlugin()],
};
```
在主进程构建中添加插件:
```ts build.ts theme={null}
import * as esbuild from 'esbuild';
import { datadogEsbuildPlugin } from '@flashcatcloud/electron-sdk/esbuild-plugin';
await esbuild.build({
entryPoints: ['src/main.ts'],
bundle: true,
platform: 'node',
outfile: 'dist/main.js',
plugins: [datadogEsbuildPlugin()],
});
```
使用打包插件时,无需再手动引入 `@flashcatcloud/electron-sdk/instrument`。插件会处理执行顺序和运行时依赖。
在 `app.whenReady()` 之后、创建第一个 `BrowserWindow` 之前调用 `init()`:
```ts main.ts theme={null}
import { app, BrowserWindow } from 'electron';
import { init } from '@flashcatcloud/electron-sdk';
void app.whenReady().then(async () => {
const initialized = await init({
applicationId: '',
clientToken: '',
service: 'my-electron-app',
env: 'production',
version: app.getVersion(),
});
if (!initialized) {
console.error('[Flashduty RUM] SDK initialization failed');
}
createWindow();
});
function createWindow(): void {
const window = new BrowserWindow();
void window.loadFile('index.html');
}
```
`applicationId`、`clientToken` 和 `service` 为必填项。SaaS 用户无需配置 `site`。初始化失败不会阻止应用继续启动;SDK 会在主进程控制台输出具体原因。
在渲染进程入口按 Web SDK 的方式初始化:
```ts renderer.ts theme={null}
import { flashcatRum } from '@flashcatcloud/browser-rum';
flashcatRum.init({
applicationId: '',
clientToken: '',
service: 'my-electron-app',
env: 'production',
version: '1.0.0',
sessionSampleRate: 100,
trackResources: true,
trackLongTasks: true,
trackUserInteractions: true,
});
```
建议让两个进程使用相同的 `applicationId`、`clientToken`、`service`、`env` 和 `version`,避免同一个应用的数据被拆到不同维度。
主进程配置正确后,SDK 会自动注入 preload 并建立桥接。你不需要修改应用自己的 preload,也不需要编写 `ipcRenderer` / `ipcMain` 转发代码。`allowedWebViewHosts` 仅用于采集 `` 或 `BrowserView` 中加载的第三方页面。
启动应用并完成一次页面访问、点击和网络请求,然后在 RUM 查看器中检查数据:
1. 使用 `source:electron OR container.source:electron` 筛选应用产生的全部 Electron 事件
2. 确认能看到主进程事件,其 `view.url` 为 `electron://main-process`
3. 确认能看到渲染进程的 `view`、`action`、`resource` 或 `error` 事件
4. 检查渲染进程事件是否带有 `container.source: electron`
默认每 10 秒上报一批数据,请等待片刻后再刷新。
同一条会话中同时出现主进程和渲染进程事件,且渲染进程事件带有 `container.source: electron`,表示双进程接入成功。
## 开启会话回放(可选)
会话回放由渲染进程录制并直接上传。请在渲染进程配置中同时设置采样率和直传开关:
```ts renderer.ts theme={null}
flashcatRum.init({
// 其余配置同上
sessionReplaySampleRate: 100,
sessionReplayDirectUpload: true,
defaultPrivacyLevel: 'mask',
});
```
回放录制需要创建 blob Worker,并从渲染进程连接上报地址。如果页面配置了 Content Security Policy(CSP),请允许 `worker-src blob:` 和实际使用的上报地址:
```html theme={null}
```
私有化部署开启回放时,还需要为渲染进程单独配置 `proxy`。配置方式见[高级配置 · 自定义上报地址](/zh/rum/sdk/electron/advanced-config#自定义上报地址)。
如果没有采集到回放,请参阅 [Electron SDK 问题排查](/zh/rum/sdk/electron/faq#为什么没有会话回放)。
## 下一步
配置自定义上报地址、批次、用户身份和手动上报 API。
了解主进程与渲染进程分别采集哪些数据。
上传 JavaScript sourcemap 和原生崩溃符号。
排查桥接、会话回放和错误还原问题。
# Flutter SDK 高级配置
Source: https://docs.flashduty.com/zh/rum/sdk/flutter/advanced-config
配置 Flutter RUM SDK 的采样率、隐私同意、事件过滤、分布式追踪和符号文件上传
本文介绍 Flutter SDK 的进阶配置项。所有配置都通过 `DatadogConfiguration` 与 `DatadogRumConfiguration` 传入。
## 采样率
```dart theme={null}
DatadogRumConfiguration(
applicationId: '',
sessionSamplingRate: 100.0, // 会话采样率
traceSampleRate: 20.0, // resource 上的追踪采样率
);
```
## 隐私同意
`TrackingConsent` 控制是否采集与上报数据,适配 GDPR 等合规要求:
| 取值 | 行为 |
| ---------------------------- | ----------------- |
| `TrackingConsent.granted` | 采集并上报 |
| `TrackingConsent.notGranted` | 不采集 |
| `TrackingConsent.pending` | 先缓存,待用户授权后决定上报或丢弃 |
```dart theme={null}
// 初始化时传入
await DatadogSdk.runApp(configuration, TrackingConsent.pending, () async {
runApp(const MyApp());
});
// 用户授权后更新
DatadogSdk.instance.setTrackingConsent(TrackingConsent.granted);
```
## 事件过滤与脱敏
事件映射器在事件上报前执行,返回 `null` 丢弃事件,或修改后返回。可用于脱敏敏感字段、去除噪声、重命名视图。
```dart theme={null}
DatadogRumConfiguration(
applicationId: '',
viewEventMapper: (event) => event,
actionEventMapper: (event) => event,
resourceEventMapper: (event) {
// 例如去除 URL 中的 query token
return event;
},
errorEventMapper: (event) => event,
longTaskEventMapper: (event) => event,
);
```
## 分布式追踪
对 `firstPartyHosts` 命中的域名,SDK 会注入 W3C `traceparent`,实现前端 RUM 与后端 APM 的链路关联。追踪需要配合网络采集(`enableHttpTracking()`)。
```dart theme={null}
import 'package:flashcat_flutter_plugin/flashcat_flutter_plugin.dart';
import 'package:flashcat_tracking_http_client/flashcat_tracking_http_client.dart';
DatadogConfiguration(
clientToken: '',
env: 'production',
site: FlashcatSite.cn,
firstPartyHosts: ['api.example.com', 'gateway.example.com'],
rumConfiguration: DatadogRumConfiguration(
applicationId: '',
traceSampleRate: 100.0,
),
)..enableHttpTracking();
```
## 自定义上报地址
私有化部署时,通过 `customEndpoint` 覆盖默认上报地址:
```dart theme={null}
DatadogRumConfiguration(
applicationId: '',
customEndpoint: 'https://your-ingest.example.com/api/v2/rum',
);
```
`customEndpoint` 是最终的 RUM intake URL,不是仅包含协议和域名的基础地址。它必须包含 `/api/v2/rum`;如果部署在路径前缀下,还需要保留该前缀,例如 `https://example.com/flashduty/api/v2/rum`。
## WebView 追踪
Flutter 页面内嵌 WebView 时,可通过 `flashcat_webview_tracking` 把 WebView 中的 Browser RUM 事件关联到当前原生 RUM 会话。
```yaml pubspec.yaml theme={null}
dependencies:
flashcat_flutter_plugin: ^0.1.3
webview_flutter: ^4.0.4
flashcat_webview_tracking: ^0.1.0
```
```dart theme={null}
import 'package:flashcat_flutter_plugin/flashcat_flutter_plugin.dart';
import 'package:flashcat_webview_tracking/flashcat_webview_tracking.dart';
import 'package:webview_flutter/webview_flutter.dart';
final webViewController = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..trackDatadogEvents(
DatadogSdk.instance,
['myapp.example'],
)
..loadRequest(Uri.parse('https://myapp.example'));
```
传给 `trackDatadogEvents` 的是允许关联的主机名列表。主机名会匹配其子域名,但不支持通配符。WebView 加载的页面必须已经接入 Flashduty Browser SDK ;Android 还必须启用 `JavaScriptMode.unrestricted`,否则无法建立关联。
## 符号文件上传
要把崩溃与错误堆栈还原到源码位置,需要上传符号文件。Flutter 应用可能同时包含 Dart 与原生帧:
| 栈帧类型 | 所需文件 | 生成方式 |
| -------------- | --------------- | -------------------------------------------------------- |
| Dart(Android) | Flutter symbols | `flutter build apk --split-debug-info= --obfuscate` |
| Dart(iOS) | 暂不支持,见下方说明 | — |
| iOS Native | dSYM | Xcode 构建产物 |
| Android Native | mapping 文件 | R8 / ProGuard 产物 |
**iOS 的 Dart 堆栈暂不支持符号化。** Flutter 为 Apple 平台生成的符号文件是 Mach-O 格式,平台当前只能解析 Android 侧的 ELF 格式,因此 iOS 的 `.symbols` 上传会被拒绝。iOS 原生崩溃不受影响,上传 dSYM 即可符号化。
如果你的应用同时发布 iOS 和 Android,`--obfuscate` 仍可开启:Android 的 Dart 堆栈会正常还原,iOS 的 Dart 堆栈则保持混淆状态。若 iOS 的可读堆栈更重要,则该端构建时不要开启 `--obfuscate`。
使用 FlashCat CLI 上传符号文件:
```bash theme={null}
# 需要 @flashcatcloud/flashcat-cli ≥ 0.2.0
FLASHCAT_API_KEY= flashcat-cli flutter-symbols upload \
--service --release-version
```
符号文件与崩溃事件是通过构建产物的 **build ID** 关联的,`service` 与 `release-version` 不参与匹配。因此二者与 SDK 初始化值不一致时,符号解析依然正常,只影响控制台「源码映射」列表中的归类与筛选。建议仍保持一致——尤其注意 Flutter 的构建号后缀(如 `1.2.3+45`)容易造成两边不一致。
真正必须对上的是 build ID:`--split-debug-info` 产出的 `app.-.symbols`、APK 内 `libapp.so`、以及控制台「源码映射 → Flutter」列表中的 Build ID 三者必须相同。每次改动 Dart 代码都会生成新的 build ID,所以**符号上传必须纳入每一次发布构建**,否则该版本的堆栈会静默退化为不解析。
## 其他配置
| 配置 | 默认值 | 说明 |
| ------------------------------- | ------------------------- | ----------------------------------------------- |
| `nativeCrashReportEnabled` | false | 是否采集原生崩溃 |
| `detectLongTasks` | true | 是否采集 long task |
| `longTaskThreshold` | 0.1s | long task 判定阈值 |
| `trackBackgroundEvents` | false | 是否采集应用后台期间的事件 |
| `vitalUpdateFrequency` | `VitalsFrequency.average` | 原生移动端性能指标的采集频率;设为 `null` 关闭 |
| `reportFlutterPerformance` | false | 是否额外采集 Flutter build / raster timing |
| `trackNonFatalAnrs` | 平台默认 | 是否采集非致命 ANR;Android 30+ 默认关闭,Android 29 及以下默认开启 |
| `appHangThreshold` | null | iOS App Hang 的判定阈值(秒);`null` 表示关闭 |
| `batchSize` / `uploadFrequency` | — | 上报批量大小与频率,权衡实时性与耗电 |
# Flutter SDK 兼容性
Source: https://docs.flashduty.com/zh/rum/sdk/flutter/compatible
了解 Flutter RUM SDK 支持的平台、Flutter 版本、伴生包和当前限制
本文说明 Flutter SDK 的支持范围和当前限制,帮助你在接入前判断工程是否满足要求。
## 支持范围
| 项目 | 支持情况 |
| -------------- | -------------------------------------------- |
| SDK 版本 | `flashcat_flutter_plugin` 0.1.3 |
| 目标平台 | **iOS 和 Android**(不支持 Flutter Web / Desktop) |
| Flutter / Dart | Flutter ≥ 3.27.0,Dart ≥ 3.6.0 |
| iOS | 部署目标 ≥ 12.0 |
| Android | `minSdkVersion` ≥ 23 |
| RUM 数据源 | 事件固定写入 `source: "flutter"` |
| 实现方式 | 基于原生 iOS / Android SDK 封装的 Flutter plugin |
| 数据上报 | `POST /api/v2/rum` |
## 包和能力
| 包 | pub 名 | 说明 |
| ------------------ | ------------------------------- | ------------------------------------------------------------- |
| RUM / Core / Crash | `flashcat_flutter_plugin` | 初始化、配置、RUM(view / action / resource / error / session)、原生崩溃采集 |
| HTTP 追踪 | `flashcat_tracking_http_client` | 自动把 `dart:io` / `http` 请求记录为 resource 并注入追踪头 |
| WebView 追踪 | `flashcat_webview_tracking` | 关联 WebView 内的 RUM 数据 |
Dart 类名以 `Datadog*` 开头,站点枚举为 `FlashcatSite`。面向客户的生产环境请使用默认的 `.cn`;私有化部署请配置完整的 `customEndpoint`。文档示例中的 `DatadogSdk`、`DatadogConfiguration`、`DatadogRumConfiguration`、`DatadogNavigationObserver` 等均为实际导出的类名。
## 支持的自动采集
| 能力 | 支持情况 | 说明 |
| ----------- | -------- | ---------------------------------------------------------------------------------- |
| 自动 view | 支持 | 需为 `MaterialApp` 添加 `DatadogNavigationObserver` |
| 自动 action | 支持 | 需用 `RumUserActionDetector` 包裹子树;`trackFrustrations` 默认开启 |
| 自动 resource | 支持(需伴生包) | 通过 `flashcat_tracking_http_client` 的 `enableHttpTracking()` |
| 未处理异常 | 支持 | 使用 `DatadogSdk.runApp` 时自动接管 `FlutterError.onError` / `PlatformDispatcher.onError` |
| 原生崩溃 | 支持 | 需 `nativeCrashReportEnabled: true` |
| 分布式追踪 | 支持 | 对 `firstPartyHosts` 命中的域名注入 W3C `traceparent` |
| 原生移动端性能指标 | 支持 | 默认采集启动耗时(TTID)、刷新率与内存 |
| 卡顿检测 | 支持 | Android 支持 ANR;iOS 设置 `appHangThreshold` 后支持 App Hang |
## 当前限制
| 限制 | 说明 |
| ---------------- | ------------------------------------------------------------------------------------ |
| 平台范围 | 仅 iOS / Android;Flutter Web 与 Desktop 不支持 |
| Logs | 不支持日志上报(`DatadogLoggingConfiguration` 为空操作) |
| Session Replay | 不支持 |
| dio / gql / grpc | 对应拦截包暂不支持 |
| Flutter 渲染耗时 | `reportFlutterPerformance` 默认关闭;仅控制 Flutter build / raster timing,不影响默认采集的原生移动端性能指标 |
| 最低版本 | 请使用 `flashcat_flutter_plugin` 0.1.3 或更高版本;更低版本 `flutter build apk --release` 会失败于 R8 |
## 符号解析兼容性
Flutter 崩溃栈可能同时包含 Dart 帧与原生(iOS / Android)帧。要把栈帧还原到源码位置,需要上传对应符号文件:
| 栈帧类型 | 所需上传文件 |
| -------------- | ------------------------------------------------------ |
| Dart(Android) | Flutter symbols(`flutter build --split-debug-info` 产物) |
| Dart(iOS) | 暂不支持,见下方说明 |
| iOS Native | dSYM |
| Android Native | mapping 文件 |
**iOS 的 Dart 堆栈暂不支持符号化。** Flutter 为 Apple 平台生成的符号文件是 Mach-O 格式,平台当前只能解析 Android 侧的 ELF 格式,因此 iOS 的 `.symbols` 上传会被拒绝。iOS 原生崩溃不受影响,上传 dSYM 即可符号化。
如果你的应用同时发布 iOS 和 Android,`--obfuscate` 仍可开启:Android 的 Dart 堆栈会正常还原,iOS 的 Dart 堆栈则保持混淆状态。若 iOS 的可读堆栈更重要,则该端构建时不要开启 `--obfuscate`。
符号文件通过 FlashCat CLI 上传。符号与崩溃事件按构建产物的 build ID 关联,因此每次改动代码后都需要重新上传该版本的符号文件。
# Flutter SDK 数据收集
Source: https://docs.flashduty.com/zh/rum/sdk/flutter/data-collection
了解 Flutter RUM SDK 采集的事件类型、字段与上报行为
本文说明 Flutter SDK 采集哪些数据、如何上报,以及如何控制采集范围。所有事件都写入 `source: "flutter"`。
## 事件类型
| 事件 | 触发方式 | 说明 |
| --------- | --------------------------------------------- | ------------------------------------------------------ |
| view | 路由切换(`DatadogNavigationObserver`)或手动 API | 一次页面停留,记录加载耗时、内部的 action / resource / error 数量 |
| action | `RumUserActionDetector` 自动识别或 `rum.addAction` | 用户交互(tap / scroll / swipe / custom),可关联 frustration 信号 |
| resource | `enableHttpTracking()` 或 `DatadogClient` | 一次网络请求,记录 URL、方法、状态码、耗时、大小 |
| error | 自动(未处理异常 / 原生崩溃)或 `rum.addError` | 错误与崩溃,含类型、消息、堆栈 |
| long task | `detectLongTasks` 默认开启 | 超过 `longTaskThreshold`(默认 0.1s)的主线程阻塞 |
## 自动采集的上下文
每个事件会自动附带以下上下文(由原生层采集):
* **应用信息**:`service`、`version`、`env`,以及 `application.id`
* **设备信息**:设备型号、操作系统与版本、屏幕尺寸
* **会话信息**:`session.id`,按 `sessionSamplingRate` 采样
* **连接信息**:网络类型(如可用)
* **用户信息**:通过 `setUserInfo` 设置的 `usr.id` / `usr.name` / `usr.email`
## 性能数据
控制台会为 Flutter 应用展示「性能」页,并支持以下原生 iOS / Android 性能数据:
| 指标 | 平台 | 说明 |
| ----------------------------- | ------------- | --------------------------------------------------------------- |
| 启动耗时(TTID) | iOS / Android | 从应用启动到首个画面完成显示的耗时 |
| 刷新率 | iOS / Android | 页面渲染流畅度 |
| 内存 | iOS / Android | 应用运行期间的内存使用情况 |
| ANR | Android | 应用无响应事件;非致命 ANR 是否默认采集取决于 Android 版本,可通过 `trackNonFatalAnrs` 覆盖 |
| App Hang | iOS | 主线程卡顿事件;需设置 `appHangThreshold`,默认关闭 |
| Flutter build / raster timing | iOS / Android | 需显式设置 `reportFlutterPerformance: true` |
启动耗时、刷新率和内存指标由 `vitalUpdateFrequency` 控制,默认为 `VitalsFrequency.average`;设置为 `null` 可关闭。`reportFlutterPerformance` 只控制 Flutter 帧的 build / raster timing,默认关闭,不影响这些原生指标。
## 手动埋点
除了自动采集,你可以手动记录事件与属性。
```dart theme={null}
final rum = DatadogSdk.instance.rum;
// 手动管理视图
rum?.startView('checkout', 'Checkout');
rum?.stopView('checkout');
// 手动记录操作
rum?.addAction(RumActionType.tap, 'pay_button');
// 手动上报错误
rum?.addErrorInfo('payment failed', RumErrorSource.source);
// 附加全局属性(写入后续所有事件)
rum?.addAttribute('tenant', 'acme');
```
## 采样与控制
| 配置 | 默认值 | 说明 |
| -------------------------- | ------------------------- | ----------------------------------------------- |
| `sessionSamplingRate` | 100.0 | 会话采样率(百分比);未命中的会话不产生 RUM 数据 |
| `traceSampleRate` | 100.0 | resource 上分布式追踪的采样率 |
| `telemetrySampleRate` | 20.0 | SDK 自身遥测采样率 |
| `detectLongTasks` | true | 是否采集 long task |
| `trackFrustrations` | true | 是否从用户操作生成 frustration 信号 |
| `trackAnonymousUser` | true | 是否为未登录用户生成匿名 ID |
| `vitalUpdateFrequency` | `VitalsFrequency.average` | 原生移动端性能指标的采集频率;设为 `null` 关闭 |
| `reportFlutterPerformance` | false | 是否采集 Flutter build / raster timing |
| `trackNonFatalAnrs` | 平台默认 | 是否采集非致命 ANR;Android 30+ 默认关闭,Android 29 及以下默认开启 |
| `appHangThreshold` | null | iOS App Hang 的判定阈值(秒);`null` 表示关闭 |
## 数据脱敏
通过事件映射器(event mapper)可以在事件上报前修改或丢弃数据,用于脱敏或过滤噪声。详见 高级配置 。
```dart theme={null}
DatadogRumConfiguration(
applicationId: '',
resourceEventMapper: (event) {
// 返回 null 丢弃事件,或修改后返回
return event;
},
);
```
## 上报行为
* SDK 在原生层做批量缓存,按 `batchSize` 与 `uploadFrequency` 分批上报
* 网络不可用时事件会持久化到本地,恢复后重试
* 上报地址默认为 `https://browser.flashcat.cloud/api/v2/rum`;私有化部署可通过 `customEndpoint` 配置完整的 RUM intake URL(必须包含 `/api/v2/rum`,并保留部署的路径前缀)
# Flutter SDK 接入
Source: https://docs.flashduty.com/zh/rum/sdk/flutter/sdk-integration
在 Flutter 应用中接入 Flashduty RUM SDK,采集视图、操作、网络、错误和崩溃数据
Flutter SDK 基于原生 iOS / Android SDK 封装,通过 `flashcat_flutter_plugin` 提供 RUM 能力。初始化后,SDK 会把应用中的视图、用户操作、网络请求、错误和崩溃事件上报到 Flashduty RUM,并使用 `source: "flutter"` 标识数据来源。
当前 SDK 版本为 `0.1.3`,支持 **iOS 和 Android** 平台(不支持 Flutter Web)。Dart 类名以 `Datadog*` 开头(如 `DatadogSdk`、`DatadogConfiguration`),站点枚举为 `FlashcatSite`。暂不支持 Logs、Session Replay,以及 dio / gql / grpc 拦截包。
## 前提条件
接入前,请先完成以下准备:
* 在 Flashduty 控制台创建或选择一个 RUM 应用,并获取 **Application ID** 和 **Client Token**
* 确认应用可以访问 `https://browser.flashcat.cloud/api/v2/rum`
* Flutter SDK ≥ 3.27.0,Dart ≥ 3.6.0;iOS 部署目标 ≥ 12.0,Android `minSdkVersion` ≥ 23
* 在应用启动早期(`main()` 中)完成 SDK 初始化
## 安装 SDK
在 `pubspec.yaml` 中添加 `flashcat_flutter_plugin`,然后执行 `flutter pub get`。
```yaml pubspec.yaml theme={null}
dependencies:
flashcat_flutter_plugin: ^0.1.3
```
请使用 `0.1.3` 或更高版本。低于该版本时,`flutter build apk --release`(包括崩溃符号化所需的 `--obfuscate` 构建)会失败于 R8,报 `Missing class org.bouncycastle.jsse.BCSSLParameters`。`0.1.3` 起所需的 ProGuard 规则随包下发,应用侧无需额外配置。
## 初始化 SDK
建议在 `main()` 中、`runApp` 之前完成初始化。使用 `DatadogSdk.runApp` 启动应用时,SDK 会自动接管 `FlutterError.onError` 与 `PlatformDispatcher.instance.onError`,无需手动接线即可采集未处理异常。
```dart main.dart theme={null}
import 'package:flutter/widgets.dart';
import 'package:flashcat_flutter_plugin/flashcat_flutter_plugin.dart';
Future main() async {
final configuration = DatadogConfiguration(
clientToken: '',
env: 'production',
service: 'com.example.shopping',
site: FlashcatSite.cn,
nativeCrashReportEnabled: true, // 采集原生 iOS / Android 崩溃
firstPartyHosts: ['api.example.com'], // 对这些域名注入分布式追踪头
rumConfiguration: DatadogRumConfiguration(
applicationId: '',
sessionSamplingRate: 100.0,
// customEndpoint: 'https://your-ingest.example.com/api/v2/rum', // 私有化 RUM 上报地址
),
);
await DatadogSdk.runApp(configuration, TrackingConsent.granted, () async {
runApp(const MyApp());
});
}
```
请不要在客户端代码中使用服务端密钥。`clientToken` 只用于客户端 RUM 数据上报,`applicationId` 用于归属 RUM 应用数据。
如果你需要在 `runApp` 之外自行控制启动流程,也可以手动初始化,但需要自己接线错误采集:
```dart theme={null}
import 'dart:ui';
WidgetsFlutterBinding.ensureInitialized();
final originalOnError = FlutterError.onError;
FlutterError.onError = (details) {
DatadogSdk.instance.rum?.handleFlutterError(details);
originalOnError?.call(details);
};
final originalPlatformOnError = PlatformDispatcher.instance.onError;
PlatformDispatcher.instance.onError = (error, stackTrace) {
DatadogSdk.instance.rum?.addErrorInfo(
error.toString(),
RumErrorSource.source,
stackTrace: stackTrace,
);
return originalPlatformOnError?.call(error, stackTrace) ?? false;
};
await DatadogSdk.instance.initialize(configuration, TrackingConsent.granted);
```
## 采集页面视图
为 `MaterialApp`(或 `CupertinoApp`)添加 `DatadogNavigationObserver`,SDK 会把 Navigator 的路由切换自动记录为 RUM 视图。
```dart theme={null}
import 'package:flashcat_flutter_plugin/flashcat_flutter_plugin.dart';
MaterialApp(
navigatorObservers: [
DatadogNavigationObserver(datadogSdk: DatadogSdk.instance),
],
home: const HomeScreen(),
);
```
`DatadogNavigationObserver` 的构造函数使用命名参数 `datadogSdk:`。默认使用路由的 `settings.name` 作为视图名称,可以通过 `viewInfoExtractor` 回调自定义视图名或过滤路由。
对于没有使用命名路由的场景,可以用 `DatadogNavigationObserverProvider` 配合 `DatadogRouteAwareMixin` 手动管理视图。
## 采集用户操作
在 RUM 配置中 `trackFrustrations` 默认开启。用 `RumUserActionDetector` 包裹应用子树后,SDK 会自动识别点击等交互并生成 action 事件;你也可以手动记录操作。
```dart theme={null}
// 自动识别子树内的用户交互
RumUserActionDetector(
rum: DatadogSdk.instance.rum,
child: const MyApp(),
);
// 手动记录一次操作
DatadogSdk.instance.rum?.addAction(RumActionType.tap, 'Checkout');
```
## 采集网络请求
自动网络采集由独立的 `flashcat_tracking_http_client` 包提供,通过配置对象上的扩展方法 `enableHttpTracking()` 开启。它会全局替换 `HttpClient`,把 `dart:io` / `http` 请求记录为 RUM resource,并对 `firstPartyHosts` 命中的域名注入 W3C 追踪头。
```yaml pubspec.yaml theme={null}
dependencies:
flashcat_tracking_http_client: ^0.1.1
```
```dart theme={null}
import 'package:flashcat_flutter_plugin/flashcat_flutter_plugin.dart';
import 'package:flashcat_tracking_http_client/flashcat_tracking_http_client.dart';
final configuration = DatadogConfiguration(
clientToken: '',
env: 'production',
site: FlashcatSite.cn,
firstPartyHosts: ['api.example.com'],
rumConfiguration: DatadogRumConfiguration(applicationId: ''),
)..enableHttpTracking();
```
## 关联用户信息
登录后,你可以设置当前用户。SDK 会把用户字段写入后续 RUM 事件的 `usr` 对象。
```dart theme={null}
DatadogSdk.instance.setUserInfo(
id: 'user-1001',
name: 'Alice',
email: 'alice@example.com',
);
```
用户退出登录时清除用户信息:
```dart theme={null}
DatadogSdk.instance.setUserInfo();
```
## 上报错误
使用 `DatadogSdk.runApp` 时未处理异常会被自动采集。你也可以手动上报捕获到的异常:
```dart theme={null}
try {
// ... 业务逻辑 ...
} catch (e, st) {
DatadogSdk.instance.rum?.addError(e, RumErrorSource.source, stackTrace: st);
}
```
崩溃与错误堆栈需要上传符号文件才能还原到源码位置。Flutter symbols、iOS dSYM、Android mapping 文件通过 FlashCat CLI 上传;每次改动代码都会生成新的构建产物,需要重新上传对应的符号文件。详见 高级配置 。
## 验证接入
完成接入后,可以按以下方式验证:
1. 在初始化时临时设置 `DatadogSdk.instance.sdkVerbosity = CoreLoggerLevel.debug`,通过控制台日志查看 SDK 上报行为
2. 运行应用并触发页面切换、点击、网络请求或手动错误
3. 在 Flashduty RUM 应用中筛选 `source:flutter`,确认出现 view、action、resource 或 error 事件
4. 对网络请求检查后端是否收到 W3C `traceparent`
## 下一步
配置采样率、隐私同意、事件过滤、追踪和符号文件上传。
了解支持的平台、Flutter 版本、伴生包和当前限制。
查看 SDK 自动和手动采集的事件类型、字段与上报行为。
# HarmonyOS SDK 高级配置
Source: https://docs.flashduty.com/zh/rum/sdk/harmony/advanced-config
配置 HarmonyOS RUM SDK 的采样、隐私同意、事件过滤、Trace、崩溃采集和符号上传
本文介绍 HarmonyOS SDK 的核心配置、RUM 配置、隐私控制、Trace 关联、崩溃采集和符号上传。所有配置均来自当前 ArkTS SDK 公开 API。
## 核心配置
核心配置通过 `ConfigurationBuilder` 创建,并传给 `Flashcat.initialize()`。
```ts theme={null}
import {
ConfigurationBuilder,
FlashcatSite
} from '@flashcatcloud/core';
const config = new ConfigurationBuilder('', 'production')
.setService('shopping-app')
.setVariant('default')
.useSite(FlashcatSite.CN)
.setBatchUploadFrequencyMs(5000)
.build();
```
| 方法 / 参数 | 类型 | 默认值 | 说明 |
| -------------------------------------------- | -------------- | ----------------- | ---------------------------------------------- |
| `new ConfigurationBuilder(clientToken, env)` | string, string | 必填 | `clientToken` 用于客户端上报鉴权;`env` 表示环境名称 |
| `setService(service)` | string | 应用 bundle id | 服务名称,写入 RUM 事件的 `service` 字段 |
| `setVariant(variant)` | string | `""` | 构建变体名称,用于区分不同产物 |
| `useSite(site)` | `FlashcatSite` | `FlashcatSite.CN` | 数据接收站点;生产环境使用 `https://browser.flashcat.cloud` |
| `setCustomEndpoint(endpoint)` | string | `""` | 覆盖上报 host,常用于本地代理或私有化转发;SDK 仍会追加 `/api/v2/rum` |
| `setBatchUploadFrequencyMs(frequencyMs)` | number | `5000` | 前台批量上报调度间隔,单位为毫秒 |
| `setVerbose(enabled)` | boolean | `false` | 输出 SDK 内部 HiLog,日志标签为 `Flashcat` |
`Flashcat.initialize()` 同一个实例名只会初始化一次。重复初始化会返回已存在实例,不会重新注册功能模块。
## 用户跟踪同意
为遵守 GDPR、CCPA 等隐私法规,SDK 要求在初始化时设置用户跟踪同意状态(`Flashcat.initialize()` 的第三个参数),并可在初始化后随时变更。
### 同意状态说明
| 状态 | 行为 | 使用场景 |
| ----------------------------- | -------------------- | --------- |
| `TrackingConsent.GRANTED` | 开始收集数据并发送到 Flashduty | 用户已同意数据收集 |
| `TrackingConsent.NOT_GRANTED` | 不收集任何数据 | 用户拒绝数据收集 |
| `TrackingConsent.PENDING` | 收集数据但不发送 | 等待用户确认 |
如果初始化时使用 `TrackingConsent.PENDING`,SDK 会将事件写入单独的本地缓冲区,但在同意状态更改为 `GRANTED` 之前不会发送;变更为 `GRANTED` 后缓冲数据自动迁移并上传,变更为 `NOT_GRANTED` 则清空缓冲。
### 应用是同意状态的唯一权威
**每次启动都以你传给 `Flashcat.initialize` 的值为准。** SDK 不会用历史状态覆盖它——这一点与 Android、iOS SDK 完全一致。你的应用负责保存用户的选择,并在每次初始化时传回给 SDK。
如果你的应用在每次启动时都用固定值(例如 `GRANTED`)初始化 SDK,那么用户撤销授权后重启,采集会重新开启。请在用户做出选择的那一刻调用 `setTrackingConsent`,并把该选择保存下来、下次启动时传给 `initialize`。
同意状态同时会被持久化到本地,但**只服务于一个用途**:后台上传使用的 `WorkSchedulerExtensionAbility` 是独立进程,它面前没有用户、也拿不到应用的判断,只能读取主进程最后一次记录的决定。详见[后台和延迟上传](#后台和延迟上传)。
撤销授权时(变更为 `NOT_GRANTED`),SDK 不仅清空未发送的 pre-consent 缓冲区,还会**删除已经落盘、尚未上传的批次**。0.2.0 及更早版本只清空缓冲区,已采集批次仍会在恢复授权后发出。
`0.3.2` 起,撤销授权还会删除用于[崩溃归因](/zh/rum/sdk/harmony/data-collection#崩溃归因)的本地 view 快照。该快照是一份完整的 view 事件,包含用户 ID、姓名、邮箱和自定义上下文,与已采集批次同样敏感。
### 设置与更改同意状态
初始化时设置:
```ts theme={null}
import { Flashcat, TrackingConsent } from '@flashcatcloud/core';
Flashcat.initialize(this.context, coreConfig, TrackingConsent.PENDING);
```
初始化后通过 `setTrackingConsent` API 更改(例如用户在隐私弹窗中做出选择后):
```ts theme={null}
Flashcat.setTrackingConsent(TrackingConsent.GRANTED);
```
Trace header 也受同意状态控制。只有状态为 `GRANTED` 时,SDK 才会向请求注入可关联的 `traceparent` 和 `tracestate`。
## RUM 配置
RUM 配置通过 `RumConfigurationBuilder` 创建,并传给 `FlashcatRum.enable()`。
```ts theme={null}
import {
FlashcatRum,
RumConfigurationBuilder
} from '@flashcatcloud/rum';
FlashcatRum.enable(
new RumConfigurationBuilder('')
.setSessionSampleRate(50)
.setTrackUserInteractions(true)
.setTrackNavigation(true)
.setTrackNetworkRequests(true)
.build()
);
```
| 方法 / 参数 | 类型 | 默认值 | 说明 |
| -------------------------------------------- | -------- | ------- | --------------------------------------------------------------------- |
| `new RumConfigurationBuilder(applicationId)` | string | 必填 | RUM 应用 ID,写入 `application.id` |
| `setSessionSampleRate(rate)` | number | `100` | 会话采样率,取值范围按百分比理解;`100` 表示全部采集,`0` 表示不采集事件 |
| `setTrackUserInteractions(enabled)` | boolean | `false` | 控制 `FlashcatRum.trackTap()` 是否记录 tap action |
| `setTrackNavigation(enabled)` | boolean | `false` | 控制 `FlashcatRum.startViewTracking()` 是否注册 ArkUI `routerPageUpdate` 监听 |
| `setTrackNetworkRequests(enabled)` | boolean | `false` | 控制 Trace 发布的网络生命周期是否转换为 RUM resource |
| `setTrackErrors(enabled)` | boolean | `true` | 控制是否**自动**采集未捕获错误和未处理的 Promise rejection |
| `setTrackFrustrations(enabled)` | boolean | `false` | 保留开关;当前版本尚未生成 frustration 事件 |
| `setEventMapper(mapper)` | function | `null` | 在事件写入磁盘前修改或丢弃 view、action、error、resource 事件 |
`setTrackErrors(false)` 只关闭**自动**错误采集。崩溃不受影响:启用 Crash 模块后,未捕获异常仍按 `JsCrashPolicy` 持久化、计数,并作为 `is_crash` error 回放到崩溃发生的那个会话;手动调用的 `addError` 属于应用的显式意图,同样照常上报。如需连这两类一起过滤,请使用 `setEventMapper()`。
### 事件过滤和脱敏
`setEventMapper()` 可以在事件上报前做轻量处理。返回修改后的事件表示继续上报,返回 `null` 表示丢弃事件。
```ts theme={null}
import { RumConfigurationBuilder } from '@flashcatcloud/rum';
const rumConfig = new RumConfigurationBuilder('')
.setEventMapper((event) => {
if (event.type === 'resource') {
const resource = event.resource as Record;
const url = resource.url;
if (typeof url === 'string') {
resource.url = url.split('?')[0];
}
}
if (event.type === 'action') {
const action = event.action as Record;
const target = action.target as Record;
if (String(target.name).includes('secret')) {
return null;
}
}
return event;
})
.build();
```
事件过滤函数运行在 SDK 写入路径上,应保持快速、同步且不抛异常。SDK 会兜底处理异常并保留原始事件,但复杂逻辑会增加端侧开销。
## 全局属性和用户信息
全局属性会合并到后续事件的 `context` 对象中。
```ts theme={null}
import {
GlobalRumMonitor,
RumErrorSource
} from '@flashcatcloud/rum';
const monitor = GlobalRumMonitor.get();
monitor.addAttribute('tenant', 'acme');
monitor.addError('checkout failed', RumErrorSource.CUSTOM);
monitor.removeAttribute('tenant');
// 读取当前全局属性快照
const attrs = monitor.getAttributes();
// 一次性清除全部全局属性(例如用户退出登录时)
monitor.clearAttributes();
```
| 方法 | 说明 |
| -------------------------- | ----------------------------------------------------------------- |
| `addAttribute(key, value)` | 新增或覆盖一个全局属性 |
| `removeAttribute(key)` | 移除指定全局属性 |
| `getAttributes()` | 返回当前全局属性的快照 |
| `clearAttributes()` | 移除全部全局属性 |
| `stopSession()` | 立即结束当前会话。活跃 view 会带着最终 `time_spent` 关闭;下一个事件会开启新会话,并在新会话中重启该 view |
用户退出登录时,建议先 `clearAttributes()` 清掉上一位用户的业务属性,再 `stopSession()` 结束会话,避免两位用户的行为落在同一个会话里。
用户信息通过核心实例设置。`id`、`name` 和 `email` 会写入后续事件的 `usr` 对象。
```ts theme={null}
import { Flashcat } from '@flashcatcloud/core';
Flashcat.getInstance().setUserInfo({
id: 'user-1001',
name: 'Alice',
email: 'alice@example.com'
});
```
当前 `setUserInfo()` 仅用于设置 `id`、`name` 和 `email`。服务端不接收其他用户字段;如需上报业务维度,请使用 RUM 全局属性或单事件属性写入 `context`。
## Trace 配置
Trace 模块负责生成 W3C `traceparent` 和 `tracestate`,并把生成的 trace id 和 span id 关联到 RUM resource 的 `_dd.trace_id` 和 `_dd.span_id` 字段。`tracestate` 会携带 Datadog vendor entry:`dd=s:{0|1};o:rum`。
```ts theme={null}
import {
FlashcatTrace,
TraceConfigurationBuilder
} from '@flashcatcloud/trace';
FlashcatTrace.enable(
new TraceConfigurationBuilder()
.setSampleRate(100)
.setFirstPartyHosts(['api.example.com'])
.build()
);
```
| 方法 | 类型 | 默认值 | 说明 |
| --------------------------- | --------- | ----- | ----------------------------------------------------------- |
| `setSampleRate(rate)` | number | `100` | 控制 `traceparent` flags 和 `tracestate` 中 sampled 标记的比例 |
| `setFirstPartyHosts(hosts)` | string\[] | `[]` | 限制 `FlashcatHttp` 只向指定一方域名及其子域名注入 Trace header;空数组表示所有 host |
当前 `setFirstPartyHosts()` 只由 `FlashcatHttp` 包装器使用。`rcp` 拦截器本身就是每个 session 的显式接入点,因此添加拦截器的 session 会对其请求注入 Trace header。请求已带有 `traceparent` 时,SDK 不会覆盖已有 Trace 上下文;已有 `tracestate` 会保留其他 vendor,并把更新后的 `dd=` 成员放在最前。
## 崩溃采集配置
Crash 模块提供两条采集路径:
* 通过 HarmonyOS `hiAppEvent` 监听 `APP_CRASH` 和 `APP_FREEZE`,在后续启动时通过 RUM error 管道上报系统回放的故障事件
* 实时处理主线程上未捕获的 ArkTS 异常,根据 `JsCrashPolicy` 在进程退出或重启前完成上报
默认的 JS 崩溃策略是 `REPORT_THEN_EXIT`。
```ts theme={null}
import {
FlashcatCrash,
CrashConfigurationBuilder,
JsCrashPolicy
} from '@flashcatcloud/crash';
FlashcatCrash.enable(
new CrashConfigurationBuilder()
.setTrackCrashes(true)
.setTrackAppHangs(true)
.setSampleRate(100)
.setJsCrashPolicy(JsCrashPolicy.REPORT_THEN_EXIT)
.build()
);
```
| 方法 | 类型 | 默认值 | 说明 |
| ------------------------------------ | --------------- | ------------------ | ---------------------------------------------------------------- |
| `setTrackCrashes(enabled)` | boolean | `true` | 监听 `hiAppEvent.APP_CRASH` 回放,包括 ArkTS 和 Native 崩溃;不控制 JS 策略的同步上报 |
| `setTrackAppHangs(enabled)` | boolean | `true` | 监听 `hiAppEvent.APP_FREEZE` 回放 |
| `setSampleRate(rate)` | number | `100` | `hiAppEvent` 崩溃和卡死事件的上报百分比;输入值限制在 `0` 到 `100`;不对 JS 策略的同步上报采样 |
| `setJsCrashPolicy(policy)` | `JsCrashPolicy` | `REPORT_THEN_EXIT` | 设置主线程上未捕获 ArkTS 异常的处理策略 |
| `setCrashLoopThreshold(threshold)` | number | `3` | 滚动窗口内第 N 次崩溃禁止再次重启,最多允许 N-1 次恢复重启;小于 `1` 的值按 `1` 处理 |
| `setCrashLoopWindowMs(windowMs)` | number | `60000` | 统计可恢复崩溃的滚动窗口,单位为毫秒;小于 `1` 的值按 `1` 处理 |
| `setCrashLoopCooldownMs(cooldownMs)` | number | `300000` | 已触发保护后,重置持久化记录所需的无崩溃时长,单位为毫秒;小于 `1` 的值按 `1` 处理 |
从 `0.2.0` 开始,默认策略由旧版的进程存活行为改为 `REPORT_THEN_EXIT`。仅初始化旧版 SDK 会在未捕获 ArkTS 异常后抑制宿主应用退出,使应用在业务状态未定义的情况下继续运行。新默认行为会同步保存崩溃并恢复平台退出语义。如需恢复旧行为,请显式设置 `JsCrashPolicy.OBSERVE_ONLY`,并确认保留受损进程符合你的业务预期。
### `REPORT_THEN_EXIT`
这是默认策略。发生主线程上未捕获的同步或异步 ArkTS 异常时,SDK 会同步持久化崩溃记录、刷新当前 RUM 写入器,然后退出进程。记录会在下一次启动时回放到 RUM。如果同步写入失败,SDK 会尝试异步上报并仍然退出。
### `REPORT_AND_RECOVER`
SDK 会同步持久化崩溃记录,检查持久化的崩溃循环保护,然后调用 `appRecovery.saveAppState()` 和 `restartApp()`。旧进程退出并启动新进程,下一次启动回放的记录会带有 `crash.recovered: true`。
如果无法启用恢复、无法持久化循环记录、保护被触发、无法把记录标记为可恢复,或重启请求失败,SDK 会降级为退出。
### `OBSERVE_ONLY`
SDK 会异步上报异常并让当前进程继续运行。该策略恢复 `0.2.0` 之前的存活行为,不会退出或重启进程。事件循环可能仍能响应,但未捕获异常可能已经使应用处于损坏或不一致的业务状态。
### 崩溃循环保护
循环保护仅影响 `REPORT_AND_RECOVER`。默认配置下,60 秒滚动窗口内前两次崩溃可以重启,第三次崩溃会同步上报但降级为退出,即窗口内第 N 次崩溃禁止重启,最多允许 N-1 次恢复重启。
崩溃时间戳会跨进程持久化,应用重启不会重置保护。保护触发后,每次被阻止的崩溃都会成为最新时间戳;应用需要保持完整的 5 分钟无崩溃冷却期,记录才会重置。将 `setCrashLoopThreshold(1)` 设为 `1` 会完全禁用恢复重启:每次崩溃仍同步上报,但都会退出,也不会标记 `crash.recovered`。
### 恢复宿主应用状态
自动重启不会自行定义需要恢复的页面状态。宿主 `UIAbility` 需要实现 `onSaveState`,把需要的状态写入 `wantParam`,并返回 `ALL_AGREE`:
```ts theme={null}
import { AbilityConstant, UIAbility } from '@kit.AbilityKit';
export default class EntryAbility extends UIAbility {
onSaveState(
_reason: AbilityConstant.StateType,
wantParam: Record
): AbilityConstant.OnSaveResult {
wantParam['route'] = 'pages/Checkout';
wantParam['draftId'] = 'draft-123';
return AbilityConstant.OnSaveResult.ALL_AGREE;
}
}
```
宿主应用需要在恢复启动的 `Want` 中读取这些参数,并且只恢复可以安全继续的状态。状态恢复依赖宿主实现 `onSaveState`,SDK 负责在崩溃时触发状态保存和重启。
### 能力边界
| 故障类型 | 采集和策略行为 |
| ---------------------- | ----------------------------------------------------------------- |
| 主线程上未捕获的 ArkTS 同步或异步异常 | 实时采集;应用所选 `JsCrashPolicy`,包括同步持久化和可选重启 |
| 未处理的 Promise rejection | 作为普通非崩溃 RUM error 上报,`error.source_type: promise`;进程不会退出,也不应用崩溃策略 |
| TaskPool 或 Worker 抛出异常 | 不会到达 error observer,不会导致宿主进程退出,不属于崩溃策略覆盖范围 |
| Native C/C++ 信号崩溃 | JS 崩溃策略无法阻止或重启;仅在后续启动时通过 `hiAppEvent.APP_CRASH` 采集 |
| `APP_FREEZE` | 仅通过 `hiAppEvent.APP_FREEZE` 在后续启动时采集 |
请在 `Flashcat.initialize()` 后尽早启用 RUM 和 Crash。JS 崩溃策略的传递不依赖启用顺序:Crash 会把策略推送给 RUM,RUM 启动时也会主动读取策略,因此先启用任一模块都能激活策略。仍建议先调用 `FlashcatRum.enable()`,再调用 `FlashcatCrash.enable()`,以便立即回放上一次启动留下的待处理崩溃记录。Crash 事件需要通过 RUM 管道发布。
## 后台和延迟上传
SDK 默认在前台按 `setBatchUploadFrequencyMs()` 的间隔上传,并在应用进入后台时触发 `flush()`。如果需要由 HarmonyOS WorkScheduler 唤醒上传,可以注册延迟上传任务。
```ts theme={null}
const config = new ConfigurationBuilder('', 'production')
.setDeferredUploadWork('FlashcatUploadAbility', 71001)
.setUploadOnWifiOnly(true)
.setDeferredUploadRequiresCharging(false)
.build();
```
| 方法 | 默认值 | 说明 |
| --------------------------------------------- | ------------------------ | ----------------------------------------------------------------- |
| `setDeferredUploadWork(abilityName, workId?)` | 未启用,`workId` 默认为 `71001` | 注册系统 WorkScheduler 任务;宿主应用需要声明对应的 `WorkSchedulerExtensionAbility` |
| `setUploadOnWifiOnly(enabled)` | `false` | 为延迟上传任务设置 Wi-Fi 网络限制 |
| `setDeferredUploadRequiresCharging(enabled)` | `true` | 为延迟上传任务设置充电状态限制 |
SDK 负责注册 WorkScheduler 任务。任务是持久化的(`isPersisted`,跨重启存活),按 2 小时周期唤醒。
### 在扩展进程中初始化
`WorkSchedulerExtensionAbility` 是**独立进程**,不共享主进程的 SDK 实例。被唤醒后必须先用 `initializeForDeferredUpload` 初始化,再调用 `flushAndWait()`:
```ts MyUploadExtensionAbility.ets theme={null}
import { Flashcat } from '@flashcatcloud/core';
async onWorkStart(workInfo: workScheduler.WorkInfo): Promise {
Flashcat.initializeForDeferredUpload(this.context, buildConfig());
await Flashcat.flushAndWait();
}
```
`initializeForDeferredUpload` 与 `initialize` 有两点关键差别:
* **不接收同意状态参数。** 扩展进程面前没有用户,只能依据主进程最后一次持久化的决定行事;没有持久化记录(主进程从未初始化过)或记录为 `NOT_GRANTED` 时,它不读取、不迁移、也不上传任何数据。
* **只读。** 它不会写回同意状态、设备标识或任务注册信息。HarmonyOS Preferences 是按进程的整文件缓存,扩展进程的写入可能覆盖主进程正在进行的撤销操作。
不要在扩展进程里调用 `Flashcat.initialize()`。它会用你传入的字面值覆盖持久化的同意状态,从而在用户已经撤销授权后仍然上传数据。`setTrackingConsent` 在扩展进程中也会被忽略并打印错误日志。
## 上传 HarmonyOS 崩溃符号
如需在控制台还原混淆后的 ArkTS 栈和 Native `.so` 栈,请使用 `@flashcatcloud/hvigor-plugin` 上传构建产物。
该插件会上传两类文件:
| 类型 | 文件 | 用途 |
| --------------- | ------------------------------------ | --------------------------- |
| ArkTS Sourcemap | `sourceMaps.map`,可选 `nameCache.json` | 还原 ArkTS / TS 文件、函数、行列号 |
| Native 符号 | 未 strip 的 `.so` 文件 | 根据 GNU build-id 解析 C/C++ 栈帧 |
该插件以 npm 包发布(在 **npm**,不在 ohpm),作为构建期开发依赖安装到工程根目录的 `package.json`,而不是 `oh-package.json5`:
```bash theme={null}
npm install -D @flashcatcloud/hvigor-plugin@^0.1.3
```
然后在模块的 `hvigorfile.ts` 中注册插件:
```ts hvigorfile.ts theme={null}
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
import { flashcatSymbolUploadPlugin } from '@flashcatcloud/hvigor-plugin';
export default {
system: hapTasks,
plugins: [
flashcatSymbolUploadPlugin({
apiKey: process.env.FLASHCAT_API_KEY ?? '',
service: 'shopping-app',
version: '1.0.0',
enabled: process.env.FLASHCAT_UPLOAD === '1'
})
]
};
```
公有云省略 `endpoint` 时,**hvigor-plugin ≥ 0.1.3** 默认上传到 `https://ci.flashcat.cloud`(**不是** RUM 上报用的 `browser.flashcat.cloud`)。私有化部署请设置环境变量 `FLASHCAT_SOURCEMAP_INTAKE_URL`(协议 + 域名,不带路径;同样需要 ≥ 0.1.3),或传 `endpoint: 'https://rum.example.com'`。旧版 0.1.2 不认 `FLASHCAT_SOURCEMAP_INTAKE_URL`,可显式写 `endpoint`,或设置旧环境变量 `FLASHCAT_ENDPOINT`(0.1.3 起弃用,但仍生效)。`flashcatSymbolUploadPlugin()` 还接受两个可选参数:`buildDir`(构建产物目录,默认 `build/default`)和 `pluginVersion`(写入上传请求头 `DD-EVP-ORIGIN-VERSION` 的版本号,默认与插件版本一致)。一般无需设置。
发布构建后执行上传任务:
```bash theme={null}
FLASHCAT_UPLOAD=1 FLASHCAT_API_KEY=*** \
hvigorw uploadFlashcatSymbols --mode module -p module=entry@default -p product=default
```
插件会向 `{endpoint}/sourcemap/upload` 发送 `multipart/form-data`:
| Header | 值 |
| ----------------------- | ------------------------ |
| `DD-API-KEY` | Flashduty API Key,用于解析账号 |
| `DD-EVP-ORIGIN` | `flashcat-hvigor-plugin` |
| `DD-EVP-ORIGIN-VERSION` | 插件版本 |
上传事件类型:
| 事件类型 | 表单字段 |
| --------------------- | ------------------------------------ |
| `harmony_sourcemap` | `event`、`source_map`、可选 `name_cache` |
| `harmony_symbol_file` | `event`、`symbol_file` |
Native 符号依赖 `.so` 的 GNU build-id。HarmonyOS NDK 默认会生成 build-id;如果你的构建链路关闭了该能力,请为 `.so` 增加 `-Wl,--build-id`。
# HarmonyOS SDK 兼容性
Source: https://docs.flashduty.com/zh/rum/sdk/harmony/compatible
了解 HarmonyOS RUM SDK 支持的工程类型、设备类型、权限、Kit 依赖和当前限制
本文说明 HarmonyOS SDK 的支持范围和当前限制,帮助你在接入前判断工程是否满足要求。
## 支持范围
| 项目 | 支持情况 |
| ------- | ---------------------------------------------------------------------- |
| 工程模型 | HarmonyOS NEXT / Stage 模型 ArkTS 工程 |
| SDK 形态 | HAR 模块,通过 `@flashcatcloud/*` 包导入 |
| RUM 数据源 | 事件固定写入 `source: "harmony"` |
| 设备类型 | SDK HAR 模块声明支持 `default`、`phone`、`tablet`、`2in1`、`tv`、`wearable`、`car` |
| 运行时初始化 | 推荐在 `AbilityStage.onCreate` 中初始化一次 |
| 数据上报 | `@kit.NetworkKit`,`POST /api/v2/rum` |
## 模块和能力
| 模块 | 包名 | 说明 |
| ------------- | ------------------------------ | ---------------------------------------------------------------------- |
| Core | `@flashcatcloud/core` | 初始化、配置、上下文、用户信息、隐私同意、持久化和上传 |
| RUM | `@flashcatcloud/rum` | view、action、resource、error 和 session |
| Trace | `@flashcatcloud/trace` | W3C `traceparent` / `tracestate` 注入、RUM resource 关联、`FlashcatHttp` 包装器 |
| Crash | `@flashcatcloud/crash` | `APP_CRASH`、`APP_FREEZE` 采集,并作为 RUM crash error 上报 |
| Hvigor plugin | `@flashcatcloud/hvigor-plugin` | 上传 ArkTS sourcemap、`nameCache.json` 和 Native `.so` 符号 |
## 权限要求
宿主应用需要允许 SDK 访问网络上报地址。
```json5 module.json5 theme={null}
{
module: {
requestPermissions: [
{
name: "ohos.permission.INTERNET"
}
]
}
}
```
如果你的应用自身需要读取网络状态,也可以声明 `ohos.permission.GET_NETWORK_INFO`。当前 SDK 的事件上下文尚未自动订阅网络状态变化,因此该权限不是 RUM 上报的必需条件。
## Kit 依赖
SDK 源码使用以下 HarmonyOS Kit:
| Kit | 使用场景 |
| ----------------------------- | ------------------------------------- |
| `@kit.AbilityKit` | 获取应用上下文、bundle 信息、异常监听、应用前后台状态 |
| `@kit.BasicServicesKit` | 读取设备品牌、型号、系统版本、API level 和设备类型 |
| `@kit.NetworkKit` | 批量上报 RUM 数据,`FlashcatHttp` 包装网络请求 |
| `@kit.RemoteCommunicationKit` | `rcp` 拦截器注入 Trace header 并记录 resource |
| `@kit.ArkUI` | 监听 `routerPageUpdate`,记录自动 view |
| `@kit.PerformanceAnalysisKit` | 监听 `hiAppEvent` 崩溃和卡死事件,输出 HiLog |
| `@kit.BackgroundTasksKit` | 注册 WorkScheduler 延迟上传任务 |
## 初始化顺序
请按以下顺序启用 SDK:
1. 调用 `Flashcat.initialize(...)` 创建核心实例
2. 调用 `FlashcatRum.enable(...)` 启用 RUM
3. 调用 `FlashcatTrace.enable(...)` 启用 Trace
4. 调用 `FlashcatCrash.enable(...)` 启用 Crash
Crash 事件通过 RUM feature 写入。请不要在未启用 RUM 的情况下只启用 `@flashcatcloud/crash`,否则收到的崩溃回放不会产生 RUM error。
## 支持的自动采集
| 能力 | 支持情况 | 说明 |
| ----------- | ------ | -------------------------------------------------------------------------------------- |
| 自动 view | 支持 | 需要启用 `setTrackNavigation(true)` 并调用 `FlashcatRum.startViewTracking(context)` |
| 自动 tap | 支持显式包装 | 需要启用 `setTrackUserInteractions(true)` 并在点击处理器中调用 `FlashcatRum.trackTap(target)` |
| 自动 resource | 支持 | 通过 `rcp` 拦截器或 `FlashcatHttp` 包装器采集 |
| 未捕获异常 | 支持 | 通过 `errorManager.on('error')` 采集 |
| 崩溃和卡死 | 支持 | 通过 `hiAppEvent` 下一次启动回放 |
| Trace 关联 | 支持 | 注入 W3C `traceparent` 和 `tracestate`,并在 RUM resource 中写入 `_dd.trace_id` / `_dd.span_id` |
## 当前限制
| 限制 | 说明 |
| -------------- | ------------------------------------------------------------------------------------------------------------------------- |
| 导航范围 | 自动 view 当前监听 ArkUI `routerPageUpdate`;`Navigation` / `NavDestination` 需要手动 view 或额外封装 |
| 点击范围 | SDK 不会自动遍历所有组件;你需要在按钮或公共点击处理器中调用 `FlashcatRum.trackTap()` |
| 网络范围 | 只有使用 `rcp` 拦截器、`FlashcatHttp` 或手动 resource API 的请求会被采集 |
| Resource 生命周期 | resource 需要在活跃 view 内结束;view 关闭时仍未结束的 resource 会被丢弃 |
| 并发 resource | 单个 view 最多保留 100 个进行中的 resource |
| rcp host 限制 | `setFirstPartyHosts()` 当前只作用于 `FlashcatHttp`;`rcp` session 添加拦截器后会对该 session 的请求注入 Trace header;请求已带有 `traceparent` 时不会覆盖 |
| 崩溃时机 | HarmonyOS 系统在下一次启动回放崩溃和卡死事件,不会在崩溃进程中同步上报 |
| 网络状态 | `connectivity.status` 当前为 `unknown` |
| Session Replay | 当前不支持 |
| 页面性能指标 | 当前不自动采集 HarmonyOS 页面渲染性能指标 |
| Frustration | `setTrackFrustrations()` 是保留开关,当前不生成 frustration 事件 |
## 符号解析兼容性
HarmonyOS 崩溃栈可能同时包含 ArkTS / JS 帧和 Native `.so` 帧。服务端会按以下方式解析:
| 栈帧类型 | 解析方式 | 所需上传文件 |
| ------------ | --------------------------------------------- | ----------------------------------------- |
| ArkTS / JS | 使用 HarmonyOS `sourceMaps.map` 还原源文件、函数名和行列号 | `sourceMaps.map`,混淆构建可附加 `nameCache.json` |
| Native C/C++ | 复用 Native 符号解析管道,通过 `build_id`、架构和 `.so` 名称匹配 | 未 strip 的 `.so` 文件,需包含 GNU build-id |
请在发布构建流程中上传符号文件,并确保 `service` 和 `version` 与 SDK 初始化和 RUM 事件中的值一致。否则控制台可以收到崩溃事件,但无法把栈帧还原到源码位置。
# HarmonyOS SDK 数据收集
Source: https://docs.flashduty.com/zh/rum/sdk/harmony/data-collection
了解 HarmonyOS RUM SDK 自动和手动采集的事件类型、字段、会话规则与上报行为
HarmonyOS SDK 将 RUM 数据组装为 NDJSON 批次并上报到 Flashduty。当前版本采集 view、action、resource 和 error 四类 RUM 事件;崩溃和卡死会作为带 `is_crash` 标记的 error 事件进入同一条管道。
## 默认上下文
SDK 初始化后,会为每条事件附加通用上下文。
| 字段 | 来源 | 说明 |
| ----------------------------------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------- |
| `source` | 固定值 | 固定为 `harmony` |
| `service` | `ConfigurationBuilder.setService()` 或应用 bundle id | 服务名称,用于按服务筛选 |
| `version` | HarmonyOS bundle 信息 | 应用版本号 |
| `application.id` | `RumConfigurationBuilder(applicationId)` | RUM 应用 ID |
| `session.id` | SDK 生成 | 用户会话 ID |
| `os.name` / `os.version` | `@kit.BasicServicesKit.deviceInfo` | 操作系统名称和版本 |
| `device.brand` / `device.model` / `device.type` | `deviceInfo` | 设备品牌、型号和类型 |
| `connectivity.status` | SDK 网络上下文 | `connected` / `not_connected` / `maybe`(`maybe` 对应 schema 的 unknown,权限缺失或接口不可用时使用) |
| `connectivity.interfaces` | SDK 网络上下文 | 当前网络接口,取值 `wifi` / `cellular` / `ethernet` / `other`,未知时为空数组 |
| `usr.id` / `usr.name` / `usr.email` | `setUserInfo()` | 已识别用户信息;服务端不接收其他用户字段 |
| `usr.anonymous_id` | SDK 持久化生成 | 匿名设备标识,随每条事件上报,用于在用户未登录时串联会话;`NOT_GRANTED` 状态下不会生成或写入 |
| `context.*` | 全局属性或单事件属性 | 自定义业务上下文 |
`clientToken` 只用于上报鉴权,不会写入 RUM 事件。
## 会话规则
SDK 按会话进行采样和生命周期管理。
| 规则 | 当前行为 |
| ---- | ------------------------------------------------------------- |
| 会话采样 | 创建会话时按 `sessionSampleRate` 做一次随机采样;未命中的会话不会写出事件 |
| 空闲超时 | 15 分钟无真实事件后过期;keep-alive 不会刷新空闲时间 |
| 最大时长 | 单个会话最长 4 小时 |
| 视图保活 | 活跃 view 每 30 秒刷新一次 `time_spent` |
| 启动条件 | `keepAlive` 不会创建新会话,只有真实 view、action、error 或 resource 事件会创建会话 |
## View 事件
View 表示用户正在查看的页面或业务视图。你可以通过自动路由追踪或手动 API 生成 view。
```ts theme={null}
import { GlobalRumMonitor } from '@flashcatcloud/rum';
const monitor = GlobalRumMonitor.get();
monitor.startView('product-detail', 'ProductDetail', {
'view.url': 'pages/ProductDetail'
});
monitor.stopView('product-detail');
```
View 事件包含:
| 字段 | 说明 |
| ---------------------- | -------------------------------------------------- |
| `view.id` | SDK 生成的唯一视图 ID |
| `view.name` | 视图名称 |
| `view.url` | 优先使用属性中的 `view.url`,否则使用 view key |
| `view.time_spent` | 从 view 开始到当前更新的耗时,单位为纳秒 |
| `view.is_active` | 当前视图是否仍处于活动状态 |
| `view.action.count` | 当前 view 下 action 数量 |
| `view.error.count` | 当前 view 下 error 数量 |
| `view.resource.count` | 当前 view 下 resource 数量 |
| `view.crash.count` | 当前 view 下 `is_crash` error 数量,用于计算 crash-free rate |
| `_dd.document_version` | 同一 view 的更新版本号 |
## Action 事件
Action 表示用户操作。即时操作通过 `addAction()` 记录,带耗时的操作通过 `startAction()` 和 `stopAction()` 记录。
```ts theme={null}
import {
GlobalRumMonitor,
RumActionType
} from '@flashcatcloud/rum';
const monitor = GlobalRumMonitor.get();
monitor.addAction(RumActionType.TAP, 'pay_button');
monitor.startAction(RumActionType.SCROLL, 'feed_scroll');
monitor.stopAction(RumActionType.SCROLL, 'feed_scroll');
```
支持的 action 类型:
| 枚举 | 值 |
| ---------------------- | -------- |
| `RumActionType.TAP` | `tap` |
| `RumActionType.SCROLL` | `scroll` |
| `RumActionType.SWIPE` | `swipe` |
| `RumActionType.CLICK` | `click` |
| `RumActionType.BACK` | `back` |
| `RumActionType.CUSTOM` | `custom` |
Action 事件包含 `action.id`、`action.type`、`action.target.name` 和 `action.loading_time`。通过 `FlashcatRum.trackTap()` 自动记录的操作类型为 `tap`。
## Resource 事件
Resource 表示网络请求。SDK 会在以下场景生成 resource:
* 使用 `rcp` session 并添加 `FlashcatTrace.interceptor()`
* 使用 `FlashcatHttp.request()` 包装 `@kit.NetworkKit` 请求
* 使用 `@flashcatcloud/axios` 的 `trackAxios()` 接入 axios 实例
* 用 `FlashcatTrace.startTracedResource()` 接入其他网络栈
以上四种都需要启用 `setTrackNetworkRequests(true)`。此外还可以通过
`GlobalRumMonitor.get().startResource()` 和 `stopResource()` 手动记录,该方式不受此开关影响。
```ts theme={null}
import {
GlobalRumMonitor,
RumResourceKind,
RumResourceMethod
} from '@flashcatcloud/rum';
const monitor = GlobalRumMonitor.get();
monitor.startResource('order-request', RumResourceMethod.GET, 'https://api.example.com/orders');
monitor.stopResource('order-request', 200, 2048, RumResourceKind.NATIVE);
```
Resource 事件包含:
| 字段 | 说明 |
| ------------------------------ | -------------------------------------------------- |
| `resource.id` | SDK 生成的资源 ID |
| `resource.type` | 资源类型;自动网络采集会按响应 `Content-Type` 归类,无法识别时使用 `native` |
| `resource.url` | 请求 URL |
| `resource.method` | 请求方法 |
| `resource.status_code` | HTTP 状态码 |
| `resource.size` | 响应体大小,单位为字节 |
| `resource.duration` | 请求耗时,单位为纳秒 |
| `_dd.trace_id` / `_dd.span_id` | 当请求注入了 `traceparent` 时写入,用于关联后端 Trace |
自动网络采集的资源类型映射:
| 响应 `Content-Type` | `resource.type` |
| --------------------- | --------------- |
| `image/*` | `image` |
| `video/*` / `audio/*` | `media` |
| `font/*` | `font` |
| `text/css` | `css` |
| `text/javascript` | `js` |
| 其他或缺失 | `native` |
如果请求失败,SDK 会生成 `source: "network"` 的 error 事件,并在 `error.resource` 中附带请求方法、状态码和 URL。
## Error 事件
Error 表示手动上报错误、未捕获 ArkTS 异常、未处理的 Promise rejection、网络错误、崩溃或卡死。
```ts theme={null}
import {
GlobalRumMonitor,
RumErrorSource
} from '@flashcatcloud/rum';
GlobalRumMonitor.get().addError(
'checkout failed',
RumErrorSource.CUSTOM,
'at checkout'
);
```
支持的 error source:
| 枚举 | 值 | 说明 |
| --------- | --------- | ------------------- |
| `NETWORK` | `network` | 网络请求失败 |
| `SOURCE` | `source` | ArkTS / JS 运行时错误或崩溃 |
| `CONSOLE` | `console` | 控制台来源错误 |
| `WEBVIEW` | `webview` | WebView 来源错误 |
| `AGENT` | `agent` | Agent 来源错误 |
| `CUSTOM` | `custom` | 业务手动上报 |
RUM 会自动监听 `errorManager.on('error')` 和 `errorManager.on('unhandledRejection')`。未处理的 Promise rejection 会作为普通非崩溃 error 上报,不会触发退出或恢复策略。
Error 事件包含:
| 字段 | 说明 |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `error.message` | 错误消息 |
| `error.source` | 错误来源 |
| `error.stack` | 错误栈,存在时上报。只包含栈帧:errorManager 回调文本里的 `Error name:` / `Error message:` / `Stacktrace:` 标签行和 sourcemap 提示行会被剥离,它们属于回调格式而非栈内容 |
| `error.handling` | `handled` 或 `unhandled` |
| `error.is_crash` | 崩溃和卡死事件为 `true` |
| `error.category` | Crash 模块写入 `Exception` 或 `App Hang` |
| `error.source_type` | Crash 模块写入 `harmony`;未处理的 Promise rejection 写入 `promise` |
| `crash.recovered` | 通过 `REPORT_AND_RECOVER` 软着陆并在后续启动回放的崩溃中存在且为 `true` |
| `crash.crashed_at_ms` | 仅在崩溃无法归因回原会话、只能记入当前会话时写入,保留真实故障发生时间(毫秒) |
| `error.binary_images` | Native 崩溃关联的动态库符号信息 |
| `build_id` | 用于匹配 Native 符号的 build-id |
## 崩溃和卡死
Crash 模块通过实时和事后两条路径采集故障:
* 主线程上未捕获的 ArkTS 异常会进入实时 JS 崩溃策略路径。`REPORT_THEN_EXIT` 和 `REPORT_AND_RECOVER` 会在进程退出或重启前同步持久化 SDK 待处理崩溃记录
* 下次启动时,Crash 模块会把 SDK 自身的待处理记录回放到 RUM,标记为已消费后删除持久化文件
* HarmonyOS `hiAppEvent` 会在后续启动时回放 `APP_CRASH` 和 `APP_FREEZE`,用于采集 ArkTS、Native C/C++ 崩溃和卡死
同一次 ArkTS 崩溃可能同时到达 `onUnhandledException`、`onException` 和后续的 `hiAppEvent.APP_CRASH`。SDK 会对两个实时回调进行指纹去重,并通过持久化的已消费记录去重系统回放,保证一次策略管理的崩溃在 RUM 管道中只生成一个 crash error 事件。
未处理的 Promise rejection 会单独采集为 `error.source_type: promise` 的普通非崩溃 RUM error。它不会使进程退出,也不会进入崩溃策略路径。
### 崩溃归因
崩溃和卡死会归因到**故障真正发生的那个会话和视图**,而不是回放它的那次启动。两类故障的归因依据不同:
* SDK 能在进程内观察到的故障(主线程上未捕获的 ArkTS 异常)在退出前会把当时的 RUM 会话和视图一并写入待处理记录,下次启动按该记录回放
* SDK 无法在进程内观察到的故障(Native 信号崩溃、卡死)会直接杀死进程,来不及记录任何东西。从 `0.3.2` 起,SDK 会把每次写出的 view 事件快照到本地,下次启动时读取(读取后立即删除)并据此还原崩溃所属的会话和视图。`0.3.1` 及更早版本会把这类故障记入重启后的实时会话,并使用回放时刻的时间,导致崩溃出现在用户并未崩溃的那个会话里,真正崩溃的会话反而显示无崩溃
回放这类故障时,SDK 会写入两条数据:一条带真实故障时间戳的 `is_crash` error,以及一份更新后的 view 文档(`document_version` 递增、`is_active` 置为 `false`、`crash` 和 `error` 计数各 +1)。两条都持久化成功后才会删除待处理记录;只有一条写入成功时会保留记录,在下次启动重试,避免会话读起来是无崩溃的。
以下情况会回退为记入**当前会话**并使用当前时间,真实故障时间保留在 `crash.crashed_at_ms` 属性中:
* view 快照对应的视图已开始超过 4 小时。这是会话的最大生命周期,此时后端上的会话已经关闭,不应再改写它的文档
* 故障发生距今已超过 23 小时。服务端会静默丢弃超过 24 小时的事件,回填时间戳会让崩溃被判定为已投递却实际丢失
* 崩溃发生在第一个会话建立之前,或本地没有可用的 view 快照
崩溃事件会通过 RUM error 管道上报:
* ArkTS / JS 错误栈会按 V8 风格帧解析
* Native C/C++ 栈会按 `#NN pc ` 形式解析
* 如果上传了 `sourceMaps.map`、`nameCache.json` 和未 strip 的 `.so`,服务端会还原源文件、函数名、行列号和 Native 符号
## 上报行为
SDK 以 NDJSON 形式批量上报事件。
| 行为 | 当前实现 |
| ---------------- | ------------------------------------------------------------------------------------ |
| 上报地址 | `{site}/api/v2/rum`,默认 site 为 `https://browser.flashcat.cloud` |
| 请求方法 | `POST` |
| Content-Type | `text/plain;charset=UTF-8` |
| Content-Encoding | `deflate`(0.3.0 起请求体默认 zlib 压缩,压缩失败时回退为未压缩上传) |
| 鉴权 | 请求头 `DD-API-KEY: ` |
| User-Agent | `flashcat-sdk-harmony/0.3.2` |
| 查询参数 | `ddsource=harmony`,`ddtags` 包含 `sdk_version:0.3.2`,并在存在时追加 `env`、`service`、`version` |
| 默认上传间隔 | 5 秒 |
| 网络超时 | 连接超时和读取超时均为 30 秒 |
| 重试 | 网络错误、`401`、`403`、`408`、`429` 和 `5xx` 会保留批次并指数退避重试 |
| 丢弃 | 其他 `4xx` 视为永久错误并丢弃当前批次 |
| 强制刷新 | error 和 crash 事件会触发更快刷新 |
| 后台刷新 | 应用进入后台时会刷新当前 view 并触发上传 |
## 当前不采集的内容
当前 HarmonyOS SDK 不自动采集以下数据:
* Session Replay
* Web Vitals 或浏览器页面性能指标
* HarmonyOS 页面渲染性能指标
* 自动 frustration 事件
# HarmonyOS SDK 接入
Source: https://docs.flashduty.com/zh/rum/sdk/harmony/sdk-integration
在 HarmonyOS NEXT 应用中接入 Flashduty RUM SDK,采集视图、操作、网络、错误和崩溃数据
HarmonyOS SDK 通过 ArkTS HAR 模块提供 RUM、Trace 和 Crash 能力。初始化后,SDK 会把应用中的视图、用户操作、网络请求、错误和崩溃事件上报到 Flashduty RUM,并使用 `source: "harmony"` 标识数据来源。
当前 SDK 模块版本为 `0.4.0`。示例使用 `@flashcatcloud/core`、`@flashcatcloud/rum`、`@flashcatcloud/trace` 和 `@flashcatcloud/crash`。使用 axios 的应用还需要 `@flashcatcloud/axios`。
## 前提条件
接入前,请先完成以下准备:
* 在 Flashduty 控制台创建或选择一个 RUM 应用,并获取 **Application ID** 和 **Client Token**
* 确认应用可以访问 `https://browser.flashcat.cloud/api/v2/rum`
* 在宿主应用中声明 `ohos.permission.INTERNET` 权限,用于 SDK 批量上报数据
* 使用 HarmonyOS NEXT / Stage 模型工程,并在应用启动早期完成 SDK 初始化
## 安装 SDK
在应用模块的 `oh-package.json5` 中添加需要的 Flashduty 模块。只接入 RUM 时至少需要 `core` 和 `rum`;需要网络 Trace 或崩溃采集时再添加对应模块。
```json5 oh-package.json5 theme={null}
{
dependencies: {
"@flashcatcloud/core": "0.4.0",
"@flashcatcloud/rum": "0.4.0",
"@flashcatcloud/trace": "0.4.0",
"@flashcatcloud/crash": "0.4.0",
// 仅在应用使用 @ohos/axios 时需要
"@flashcatcloud/axios": "0.4.0"
}
}
```
## 初始化 SDK
建议在 `AbilityStage.onCreate` 中初始化 SDK。这样可以在页面、网络请求和异常发生前完成核心实例、RUM、Trace 和 Crash 功能注册。
```ts MyAbilityStage.ets theme={null}
import { AbilityStage } from '@kit.AbilityKit';
import {
Flashcat,
ConfigurationBuilder,
FlashcatSite,
TrackingConsent
} from '@flashcatcloud/core';
import {
FlashcatRum,
RumConfigurationBuilder
} from '@flashcatcloud/rum';
import {
FlashcatTrace,
TraceConfigurationBuilder
} from '@flashcatcloud/trace';
import {
FlashcatCrash,
CrashConfigurationBuilder
} from '@flashcatcloud/crash';
export default class MyAbilityStage extends AbilityStage {
onCreate(): void {
const coreConfig = new ConfigurationBuilder('', 'production')
.setService('shopping-app')
.setVariant('default')
.useSite(FlashcatSite.CN)
.build();
Flashcat.initialize(this.context, coreConfig, TrackingConsent.GRANTED);
FlashcatRum.enable(
new RumConfigurationBuilder('')
.setSessionSampleRate(100)
.setTrackUserInteractions(true)
.setTrackNavigation(true)
.setTrackNetworkRequests(true)
.build()
);
FlashcatTrace.enable(
new TraceConfigurationBuilder()
.setSampleRate(100)
.setFirstPartyHosts(['api.example.com'])
.build()
);
FlashcatCrash.enable(new CrashConfigurationBuilder().build());
}
}
```
请不要在客户端代码中使用服务端密钥。`clientToken` 只用于客户端 RUM 数据上报,`applicationId` 用于归属 RUM 应用数据。
## 采集页面视图
如果应用使用 ArkUI `router`,请在 UI 页面拿到 `UIContext` 后启动自动视图追踪。该能力只有在 RUM 配置中启用 `setTrackNavigation(true)` 后才会生效。
```ts pages/Index.ets theme={null}
import { FlashcatRum } from '@flashcatcloud/rum';
@Entry
@Component
struct Index {
aboutToAppear(): void {
FlashcatRum.startViewTracking(this.getUIContext());
}
}
```
自动视图追踪会监听 `routerPageUpdate`:
| 页面状态 | SDK 行为 |
| -------------- | --------------------------------------- |
| `ON_PAGE_SHOW` | 生成 `startView`,视图名称优先使用路由名称,缺省时使用路径最后一段 |
| `ON_PAGE_HIDE` | 生成 `stopView`,关闭当前视图并刷新停留时长 |
如果你的页面没有使用 `router`,可以使用手动 API 管理视图。
```ts theme={null}
import { GlobalRumMonitor } from '@flashcatcloud/rum';
const monitor = GlobalRumMonitor.get();
monitor.startView('checkout', 'Checkout');
monitor.stopView('checkout');
```
## 采集用户操作
启用 `setTrackUserInteractions(true)` 后,可以通过 `FlashcatRum.trackTap()` 在统一点击处理器中记录点击事件。该方法不会自动遍历所有组件,你需要在按钮或公共事件封装处显式调用。
```ts theme={null}
import { FlashcatRum } from '@flashcatcloud/rum';
Button('Pay')
.onClick(() => {
FlashcatRum.trackTap('pay_button');
// 执行业务逻辑
});
```
你也可以通过 `GlobalRumMonitor` 手动记录即时操作或带耗时的操作。
```ts theme={null}
import {
GlobalRumMonitor,
RumActionType
} from '@flashcatcloud/rum';
const monitor = GlobalRumMonitor.get();
monitor.addAction(RumActionType.TAP, 'checkout_button');
monitor.startAction(RumActionType.SCROLL, 'product_feed');
monitor.stopAction(RumActionType.SCROLL, 'product_feed');
```
## 采集网络请求和 Trace
HarmonyOS SDK 按网络库提供三种接入方式。**它们都只有在 RUM 配置中启用 `setTrackNetworkRequests(true)` 后才会生成 resource 事件,该开关默认关闭。**
| 应用使用的网络库 | 接入方式 |
| ------------------------------------- | -------------------------------------------- |
| `@kit.RemoteCommunicationKit` 的 `rcp` | 添加 `FlashcatTrace.interceptor()` |
| `@kit.NetworkKit` | 改用 `FlashcatHttp.request()` |
| `@ohos/axios` | 调用 `trackAxios(instance)` |
| 其他网络栈 | 用 `FlashcatTrace.startTracedResource()` 自行接入 |
SDK 不会自动挂钩 `@kit.NetworkKit` 的 `http.createHttp()`。直接用它发起的请求不会被采集,请改用上表中对应的接入方式。
### rcp 拦截器
如果应用使用 `@kit.RemoteCommunicationKit` 的 `rcp`,在 session 中添加 `FlashcatTrace.interceptor()`。拦截器会注入 W3C `traceparent` 和 `tracestate`,并把请求生命周期发送给 RUM 生成 resource 事件。
```ts theme={null}
import { rcp } from '@kit.RemoteCommunicationKit';
import { FlashcatTrace } from '@flashcatcloud/trace';
const session = rcp.createSession({
interceptors: [FlashcatTrace.interceptor()]
});
const response = await session.get('https://api.example.com/orders');
session.close();
```
### FlashcatHttp 包装器
如果应用使用 `@kit.NetworkKit`,可以用 `FlashcatHttp.request()` 替代 `http.createHttp().request(...)`。该包装器会在请求完成或失败时生成 RUM resource 或 network error。
```ts theme={null}
import { http } from '@kit.NetworkKit';
import { FlashcatHttp } from '@flashcatcloud/trace';
const response = await FlashcatHttp.request('https://api.example.com/orders', {
method: http.RequestMethod.GET
});
```
### axios
`@ohos/axios` 有自己的网络适配层,不经过上面两条路径,需要安装 `@flashcatcloud/axios` 并对每个 axios 实例调用一次 `trackAxios()`。
```ts theme={null}
import axios from '@ohos/axios';
import { trackAxios } from '@flashcatcloud/axios';
const apiClient = axios.create({ baseURL: 'https://api.example.com' });
trackAxios(apiClient);
```
放在你已经创建 axios 实例的地方即可,通常是统一封装 token 和错误处理的那个文件。
拦截器是**按实例**注册的:`axios` 默认导出和 `axios.create()` 创建的实例互不共享。每个需要上报的实例都要调用一次,且**只调一次**——重复调用会导致同一请求上报两次。
### 其他网络栈
自研网络库或上面未覆盖的三方库,用 `FlashcatTrace.startTracedResource()` 接入。它登记 resource 并返回要注入的请求头,采集同意与一方域名门控、采样判断、id 编码都在 SDK 内部完成。
```ts theme={null}
import { FlashcatTrace, TracedResource } from '@flashcatcloud/trace';
const traced: TracedResource = FlashcatTrace.startTracedResource(url, 'GET');
// 把 traced.headers 合并进请求后再发送
try {
const response = await send(url, traced.headers);
FlashcatTrace.stopTracedResource(traced.key, response.status, response.size);
} catch (e) {
// 拿到了响应(哪怕是 404)应传给 stopTracedResource,保留为对应状态码的
// resource;只有完全没拿到响应的传输失败才用 failTracedResource。
FlashcatTrace.failTracedResource(traced.key, `${e}`);
}
```
务必传入**完整 URL**:相对路径解析不出域名,一方域名检查会因此跳过注入,resource 上也会缺少 host。每次 `startTracedResource` 都要配对一次 `stopTracedResource` 或 `failTracedResource`,包括失败路径,否则 resource 不会关闭。
`traceparent` 和 `tracestate` 只有在追踪同意状态为 `TrackingConsent.GRANTED` 时才会注入,并按 `setFirstPartyHosts()` 限制注入域名;未配置一方域名时会对所有 host 注入。请求已带有 `traceparent` 时,SDK 不会覆盖已有 Trace 上下文。以上对四种接入方式一致生效。
## 关联用户信息
登录后,你可以设置当前用户。SDK 会把用户字段写入后续 RUM 事件的 `usr` 对象。
```ts theme={null}
import { Flashcat } from '@flashcatcloud/core';
Flashcat.getInstance().setUserInfo({
id: 'user-1001',
name: 'Alice',
email: 'alice@example.com'
});
```
当前 `setUserInfo()` 仅用于设置 `id`、`name` 和 `email`。服务端不接收其他用户字段;如需上报业务维度,请使用 RUM 全局属性或单事件属性写入 `context`。
用户退出登录时清除用户信息。
```ts theme={null}
Flashcat.getInstance().clearUserInfo();
```
## 验证接入
完成接入后,可以按以下方式验证:
1. 在初始化配置中临时启用 `setVerbose(true)`,通过 HiLog 查看 `Flashcat` 标签日志
2. 打开应用并触发页面切换、按钮点击、网络请求或手动错误
3. 在 Flashduty RUM 应用中筛选 `source:harmony`,确认出现 view、action、resource 或 error 事件
4. 对网络请求检查后端 Trace 是否收到 `traceparent`
5. 触发 Crash 功能后重新启动应用;HarmonyOS 系统会在下一次启动时回放崩溃事件
## 下一步
配置采样率、隐私同意、事件过滤、Trace 和崩溃符号上传。
了解支持的 HarmonyOS 工程、Kit、权限和当前限制。
查看 SDK 自动和手动采集的事件类型、字段与上报行为。
# iOS SDK 高级配置
Source: https://docs.flashduty.com/zh/rum/sdk/ios/advanced-config
深入配置 iOS RUM SDK 的高级功能,包括自定义事件、用户追踪、采样控制和数据安全
**关于依赖和包名的说明**
Flashduty iOS SDK 完全兼容 Datadog 开源协议。在 Swift Package Manager 或 CocoaPods 中添加依赖时使用 `FlashcatCore`、`FlashcatRUM` 等名称,但在代码中 import 时使用 `DatadogCore`、`DatadogRUM` 等模块名。您可以无缝复用 Datadog 生态的文档、示例和最佳实践,同时享受 Flashduty 平台的服务。
Flashduty iOS RUM SDK 提供丰富的高级配置选项,帮助您根据业务需求定制数据收集和上下文信息。
**支持的配置场景:**
* 保护敏感数据 - 屏蔽个人身份信息等敏感数据
* 关联用户会话 - 将用户会话与内部用户标识关联
* 减少数据量 - 通过采样降低 RUM 数据收集量,优化成本
* 增强上下文 - 为数据添加自定义属性
## 丰富用户会话
### 自定义视图
默认情况下,RUM SDK 会自动追踪 `UIViewController` 或 SwiftUI `View`。您也可以手动追踪特定的视图或为自动追踪的视图添加自定义属性。
调用 `RUMMonitor.shared().startView()` 开始追踪新的 RUM 视图。同一 `key` 的所有视图将被分组在 RUM Explorer 中。
```swift theme={null}
import DatadogRUM
// 在您的 UIViewController 中
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
RUMMonitor.shared().startView(
key: "view-key",
name: "View Name",
attributes: ["foo": "bar"]
)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
RUMMonitor.shared().stopView(
key: "view-key",
attributes: ["foo": "bar"]
)
}
```
```objective-c theme={null}
@import DatadogObjc;
// 在您的 UIViewController 中
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[RUMMonitor shared] startViewWithKey:@"view-key"
name:@"View Name"
attributes:@{@"foo": @"bar"}];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[[RUMMonitor shared] stopViewWithKey:@"view-key"
attributes:@{@"foo": @"bar"}];
}
```
### 自定义操作
除了自动追踪用户操作外,您还可以手动追踪特定的自定义操作(如点击、滚动、滑动等)。
```swift theme={null}
import DatadogRUM
// 在您的 UIViewController 中
@IBAction func didTapDownloadResourceButton(_ sender: UIButton) {
RUMMonitor.shared().addAction(
type: .tap,
name: sender.currentTitle ?? "",
attributes: ["resource_id": "123"]
)
}
```
```objective-c theme={null}
@import DatadogObjc;
- (IBAction)didTapDownloadResourceButton:(UIButton *)sender {
[[RUMMonitor shared] addActionWithType:RUMActionTypeTap
name:sender.currentTitle
attributes:@{@"resource_id": @"123"}];
}
```
使用 `addAction()` 时,RUM SDK 会创建一个 RUM 操作,并将所有新的资源、错误和长任务附加到此操作,直到视图被视为已完成加载。
### 自定义资源
Flashduty iOS SDK 会自动追踪通过启用的 `URLSession` 发起的网络请求。您也可以手动追踪自定义资源(如第三方 API、GraphQL 查询等)。
```swift theme={null}
import DatadogRUM
// 在您的网络客户端中
RUMMonitor.shared().startResource(
resourceKey: "resource-key",
request: request,
attributes: ["foo": "bar"]
)
// 加载成功时
RUMMonitor.shared().stopResource(
resourceKey: "resource-key",
response: response,
size: size,
attributes: ["foo": "bar"]
)
// 加载失败时
RUMMonitor.shared().stopResourceWithError(
resourceKey: "resource-key",
error: error,
attributes: ["foo": "bar"]
)
```
```objective-c theme={null}
@import DatadogObjc;
// 在您的网络客户端中
[[RUMMonitor shared] startResourceWithResourceKey:@"resource-key"
request:request
attributes:@{@"foo": @"bar"}];
// 加载成功时
[[RUMMonitor shared] stopResourceWithResourceKey:@"resource-key"
response:response
size:size
attributes:@{@"foo": @"bar"}];
```
用于调用的 `resourceKey` 必须唯一,才能使 RUM iOS SDK 将资源的开始与其完成匹配。
### 自定义错误
要追踪特定错误,当错误发生时通知 `RUMMonitor`:
```swift theme={null}
import DatadogRUM
RUMMonitor.shared().addError(
message: "Error message",
type: "ErrorType",
source: .source,
stack: "Error stack trace",
attributes: ["foo": "bar"],
file: #file,
line: #line
)
```
```objective-c theme={null}
@import DatadogObjc;
[[RUMMonitor shared] addErrorWithMessage:@"Error message"
type:@"ErrorType"
source:DDRUMErrorSourceCustom
stack:@"Error stack trace"
attributes:@{@"foo": @"bar"}
file:file
line:line];
```
更多错误上报详情,请参阅 [iOS 异常上报](/zh/rum/error-tracking/erro-reporting/ios)。
## 追踪自定义全局属性
iOS SDK 会自动捕获默认 RUM 属性。您还可以向 RUM 事件添加额外的上下文信息,例如自定义属性。
**自定义属性的用途:**
* 根据业务信息(如购物车价值、用户等级、广告活动)过滤和分组用户行为
* 跟踪特定用户群体的性能表现
* 了解不同用户群体的错误分布
### 设置自定义全局属性
```swift theme={null}
import DatadogRUM
// 添加全局属性
RUMMonitor.shared().addAttribute(forKey: "user_plan", value: "premium")
// 删除全局属性
RUMMonitor.shared().removeAttribute(forKey: "user_plan")
```
```objective-c theme={null}
@import DatadogObjc;
// 添加全局属性
[[RUMMonitor shared] addAttributeForKey:@"user_plan" value:@"premium"];
// 删除全局属性
[[RUMMonitor shared] removeAttributeForKey:@"user_plan"];
```
**保留键名:**\
不能使用以下键名,因为它们被 SDK 内部使用:`date`、`error.kind`、`error.message`、`error.stack`、`error.source_type`、`view.id`、`view.url`、`view.loading_time`、`view.referrer`、`application.id`
## 追踪用户会话
为 RUM 会话添加用户信息,帮助您更好地了解用户行为和问题影响。
**用户信息的用途:**
* 跟踪特定用户的浏览路径
* 了解哪些用户受错误影响最大
* 监控关键用户的性能表现
```swift theme={null}
import DatadogCore
Datadog.setUserInfo(
id: "1234",
name: "John Doe",
email: "john@doe.com"
)
```
```objective-c theme={null}
@import DatadogObjc;
[DDDatadog setUserInfoWithId:@"1234"
name:@"John Doe"
email:@"john@doe.com"
extraInfo:nil];
```
当前仅支持设置用户标准字段:`id`、`name`、`email`、`anonymous_id`;其他用户属性不支持。如有需求,可以在 `context` 字段进行配置。
**参数说明:**
* `usr.id` (字符串) - 唯一用户标识符
* `usr.name` (字符串) - 用户友好名称,默认在 RUM UI 中显示
* `usr.email` (字符串) - 用户电子邮件,若无名称则显示邮件
* 以上属性均为可选,建议至少提供一个
## 追踪后台事件
您可以追踪应用在后台运行时的事件(如崩溃和网络请求)。
```swift theme={null}
import DatadogRUM
RUM.enable(
with: RUM.Configuration(
applicationID: "",
trackBackgroundEvents: true
)
)
```
```objective-c theme={null}
@import DatadogObjc;
DDRUMConfiguration *configuration = [[DDRUMConfiguration alloc]
initWithApplicationID:@""];
configuration.trackBackgroundEvents = YES;
[RUM enableWith:configuration];
```
追踪后台事件可能会产生额外的会话,从而影响计费。如有疑问,请联系 Flashduty 支持团队。
## 初始化参数
在创建 SDK 配置时,可以设置以下属性:
| 参数 | 类型 | 必填 | 说明 |
| ----------------- | --------------- | -- | -------------------------------------- |
| `clientToken` | String | ✅ | 客户端令牌 |
| `env` | String | ✅ | 环境名称(如 `production`、`staging`) |
| `service` | String | 可选 | 服务名称,默认为应用 bundle 标识符 |
| `batchSize` | BatchSize | 可选 | 批量上传数据大小(`.small`、`.medium`、`.large`) |
| `uploadFrequency` | UploadFrequency | 可选 | 数据上传频率(`.frequent`、`.average`、`.rare`) |
创建 RUM 配置时可以设置以下参数:
| 参数 | 类型 | 必填 | 说明 |
| ------------------------- | -------------------------- | -- | -------------------------- |
| `applicationID` | String | 是 | RUM 应用 ID |
| `sessionSampleRate` | Float | 否 | 会话采样率 (0-100),默认 100 |
| `uiKitViewsPredicate` | UIKitRUMViewsPredicate | 否 | UIKit 视图追踪策略 |
| `uiKitActionsPredicate` | UIKitRUMActionsPredicate | 否 | UIKit 操作追踪策略 |
| `swiftUIViewsPredicate` | SwiftUIRUMViewsPredicate | 否 | SwiftUI 视图追踪策略 |
| `swiftUIActionsPredicate` | SwiftUIRUMActionsPredicate | 否 | SwiftUI 操作追踪策略 |
| `urlSessionTracking` | URLSessionTracking | 否 | URLSession 网络请求追踪配置 |
| `trackBackgroundEvents` | Bool | 可选 | 是否追踪后台事件,默认 `false` |
| `trackFrustrations` | Bool | 可选 | 是否追踪用户挫败感(如错误点击),默认 `true` |
| `trackLongTasks` | Bool | 可选 | 是否追踪长任务,默认 `true` |
\| `longTaskThreshold` | TimeInterval | 否 | 长任务阈值(秒),默认 0.1 秒 |
\| `vitalsUpdateFrequency` | VitalsFrequency | 否 | 性能指标更新频率,可选: `.frequent`, `.average`, `.rare`, `.never` |
### 自动追踪视图
要启用视图自动追踪,在初始化 RUM 时设置 `uiKitViewsPredicate` 或 `swiftUIViewsPredicate`。
对于 **UIKit**,使用 `DefaultUIKitRUMViewsPredicate` 类:
```swift theme={null}
import DatadogRUM
RUM.enable(
with: RUM.Configuration(
applicationID: "",
uiKitViewsPredicate: DefaultUIKitRUMViewsPredicate()
)
)
```
对于 **SwiftUI**,使用 `DefaultSwiftUIRUMViewsPredicate` 类:
```swift theme={null}
import DatadogRUM
RUM.enable(
with: RUM.Configuration(
applicationID: "",
swiftUIViewsPredicate: DefaultSwiftUIRUMViewsPredicate()
)
)
```
您还可以实现自定义的 `predicate` 来自定义追踪行为。
### 自动追踪用户操作
要启用用户操作自动追踪,在初始化 RUM 时设置 `uiKitActionsPredicate` 或 `swiftUIActionsPredicate`。
对于 **UIKit**:
```swift theme={null}
import DatadogRUM
RUM.enable(
with: RUM.Configuration(
applicationID: "",
uiKitActionsPredicate: DefaultUIKitRUMActionsPredicate()
)
)
```
对于 **SwiftUI**:
```swift theme={null}
import DatadogRUM
RUM.enable(
with: RUM.Configuration(
applicationID: "",
swiftUIActionsPredicate: DefaultSwiftUIRUMActionsPredicate(isLegacyDetectionEnabled: true)
)
)
```
### 自动追踪网络请求
要启用网络请求自动追踪(资源和错误),在初始化 RUM 时设置 `urlSessionTracking` 并启用 `URLSessionInstrumentation`:
```swift theme={null}
import DatadogRUM
RUM.enable(
with: RUM.Configuration(
applicationID: "",
urlSessionTracking: RUM.Configuration.URLSessionTracking()
)
)
URLSessionInstrumentation.enable(
with: .init(
delegateClass: SessionDelegate.self
)
)
```
您还可以配置 `firstPartyHostsTracing` 以启用分布式追踪,将 RUM 资源与后端 traces 关联:
```swift theme={null}
import DatadogRUM
RUM.enable(
with: RUM.Configuration(
applicationID: "",
urlSessionTracking: RUM.Configuration.URLSessionTracking(
firstPartyHostsTracing: .trace(hosts: ["example.com", "api.example.com"])
)
)
)
```
### 自动追踪错误
所有"致命"和"非致命"的 iOS 错误都会自动收集并附加当前 RUM 视图的完整错误详情和元数据。
致命错误包括应用崩溃。非致命错误包括:
* **Swift errors**: Swift `throw` 的错误
* **Objective-C exceptions**: Objective-C 异常
您可以通过 RUM Explorer 和 Error Tracking 查看错误详情。
## 修改或丢弃 RUM 事件
在 RUM 事件发送到 Flashduty 之前,您可以通过事件映射器(Event Mappers)对其进行修改或完全丢弃。
事件映射器在创建 RUM 配置时设置:
```swift theme={null}
import DatadogRUM
let configuration = RUM.Configuration(
applicationID: "",
viewEventMapper: { RUMViewEvent in
return RUMViewEvent
},
errorEventMapper: { RUMErrorEvent in
return RUMErrorEvent
},
resourceEventMapper: { RUMResourceEvent in
return RUMResourceEvent
},
actionEventMapper: { RUMActionEvent in
return RUMActionEvent
},
longTaskEventMapper: { RUMLongTaskEvent in
return RUMLongTaskEvent
}
)
RUM.enable(with: configuration)
```
```objective-c theme={null}
@import DatadogObjc;
DDRUMConfiguration *configuration = [[DDRUMConfiguration alloc] initWithApplicationID:@""];
[configuration setViewEventMapper:^DDRUMViewEvent * _Nonnull(DDRUMViewEvent * _Nonnull RUMViewEvent) {
return RUMViewEvent;
}];
[configuration setErrorEventMapper:^DDRUMErrorEvent * _Nullable(DDRUMErrorEvent * _Nonnull RUMErrorEvent) {
return RUMErrorEvent;
}];
[configuration setResourceEventMapper:^DDRUMResourceEvent * _Nullable(DDRUMResourceEvent * _Nonnull RUMResourceEvent) {
return RUMResourceEvent;
}];
[configuration setActionEventMapper:^DDRUMActionEvent * _Nullable(DDRUMActionEvent * _Nonnull RUMActionEvent) {
return RUMActionEvent;
}];
[configuration setLongTaskEventMapper:^DDRUMLongTaskEvent * _Nullable(DDRUMLongTaskEvent * _Nonnull RUMLongTaskEvent) {
return RUMLongTaskEvent;
}];
```
每个映射器都是一个签名为 `(T) -> T?` 的 Swift 闭包,其中 `T` 是具体的 RUM 事件类型。这允许在事件发送之前更改部分事件。
例如,要屏蔽 RUM Resource 的 `url` 中的敏感信息,实现一个自定义的 `redacted(_:) -> String` 函数并在 `resourceEventMapper` 中使用它:
```swift theme={null}
let configuration = RUM.Configuration(
applicationID: "",
resourceEventMapper: { RUMResourceEvent in
var RUMResourceEvent = RUMResourceEvent
RUMResourceEvent.resource.url = redacted(RUMResourceEvent.resource.url)
return RUMResourceEvent
}
)
```
```objective-c theme={null}
DDRUMConfiguration *configuration = [[DDRUMConfiguration alloc] initWithApplicationID:@""];
[configuration setResourceEventMapper:^DDRUMResourceEvent * _Nullable(DDRUMResourceEvent * _Nonnull RUMResourceEvent) {
return RUMResourceEvent;
}];
```
从 error、resource 或 action 映射器返回 `nil` 将完全丢弃该事件;该事件不会发送到 Flashduty。从 view 事件映射器返回的值不能为 `nil`(要丢弃视图,请自定义 `UIKitRUMViewsPredicate` 的实现;详见[追踪视图自动化](https://docs.flashduty.com/zh/flashduty/rum/ios-sdk-integration#自动追踪视图))。
根据事件的类型,只有某些特定的属性可以被修改:
| 事件类型 | 属性键 | 说明 |
| ---------------- | ------------------------------------ | -------------- |
| RUMActionEvent | `RUMActionEvent.action.target?.name` | 操作名称 |
| | `RUMActionEvent.view.url` | 与此操作关联的视图 URL |
| RUMErrorEvent | `RUMErrorEvent.error.message` | 错误消息 |
| | `RUMErrorEvent.error.stack` | 错误堆栈跟踪 |
| | `RUMErrorEvent.error.resource?.url` | 错误引用的资源 URL |
| | `RUMErrorEvent.view.url` | 与此错误关联的视图 URL |
| RUMResourceEvent | `RUMResourceEvent.resource.url` | 资源 URL |
| | `RUMResourceEvent.view.url` | 与此资源关联的视图 URL |
| RUMViewEvent | `RUMViewEvent.view.name` | 视图名称 |
| | `RUMViewEvent.view.url` | 视图 URL |
| | `RUMViewEvent.view.referrer` | 链接到页面初始视图的 URL |
## 获取 RUM 会话 ID
检索 RUM 会话 ID 对于故障排查非常有用。例如,您可以将会话 ID 附加到支持请求、电子邮件或错误报告中,以便您的支持团队稍后在 Flashduty 中找到用户会话。
您可以在运行时访问 RUM 会话 ID,无需等待 `sessionStarted` 事件:
```swift theme={null}
import DatadogRUM
RUMMonitor.shared().currentSessionID(completion: { sessionId in
currentSessionId = sessionId
})
```
```objective-c theme={null}
@import DatadogObjc;
[[RUMMonitor shared] currentSessionIDWithCompletion:^(NSString * _Nullable sessionId) {
// use session ID
}];
```
## 设置追踪同意(GDPR 合规)
为符合 GDPR 法规,Flashduty iOS SDK 在初始化时需要追踪同意值。
`trackingConsent` 设置可以是以下值之一:
1. `.pending`: Flashduty iOS SDK 开始收集和批处理数据,但不发送到 Flashduty。SDK 等待新的追踪同意值来决定如何处理批处理的数据。
2. `.granted`: Flashduty iOS SDK 开始收集数据并发送到 Flashduty。
3. `.notGranted`: iOS SDK 不收集任何数据。不会发送日志、traces 或 RUM 事件。
在 SDK 初始化后更改追踪同意值,请使用 `Datadog.set(trackingConsent:)` API 调用。SDK 会根据新值更改其行为。
例如,如果当前追踪同意是 `.pending`:
* 如果您将值更改为 `.granted`,SDK 将发送所有当前和未来的数据到 Flashduty;
* 如果您将值更改为 `.notGranted`,SDK 将清除所有当前数据并且不收集未来的数据。
```swift theme={null}
import DatadogCore
Datadog.set(trackingConsent: .granted)
```
```objective-c theme={null}
@import DatadogObjc;
[DDDatadog setWithTrackingConsent:DDTrackingConsentGranted];
```
## 添加用户属性
当前仅支持设置用户标准字段:`id`、`name`、`email`、`anonymous_id`;其他用户属性不支持。如有需求,可以在 `context` 字段进行配置。
## 数据管理
### 清除所有数据
您可以选择删除 SDK 存储的所有未发送数据,使用 `Datadog.clearAllData()` API:
```swift theme={null}
import DatadogCore
Datadog.clearAllData()
```
```objective-c theme={null}
@import DatadogObjc;
[DDDatadog clearAllData];
```
### 停止数据收集
您可以使用 `Datadog.stopInstance()` API 停止命名的 SDK 实例(如果名称为 `nil` 则停止默认实例)进一步收集和上传数据。
```swift theme={null}
import DatadogCore
Datadog.stopInstance()
```
```objective-c theme={null}
@import DatadogObjc;
[DDDatadog stopInstance];
```
调用此方法会禁用 SDK 和所有活跃的功能,如 RUM。要恢复数据收集,您必须重新初始化 SDK。如果您想动态更改配置,可以使用此 API。
## 采样
默认情况下,RUM 会收集所有会话的数据。您可以通过 `sessionSampleRate` 参数设置采样率(百分比)来减少收集的会话数量。例如,采集 90% 的会话:
```swift theme={null}
import DatadogRUM
RUM.enable(
with: RUM.Configuration(
applicationID: "",
sessionSampleRate: 90
)
)
```
```objective-c theme={null}
@import DatadogObjc;
DDRUMConfiguration *configuration = [[DDRUMConfiguration alloc] initWithApplicationID:@""];
configuration.sessionSampleRate = 90;
[RUM enableWith:configuration];
```
被采样的会话将不收集任何视图及其相关遥测数据。
## 集成 RUM 与分布式追踪
集成 RUM 与分布式追踪,可让您将 iOS 应用程序的请求与其对应的后端跟踪关联起来。这种组合让您能够一目了然地查看完整的前端和后端数据。
使用来自 RUM 的前端数据以及来自 trace ID 注入的后端、基础设施和日志信息来定位堆栈中任何地方的问题并了解用户的体验。
### 配置方法
初始化 RUM SDK,使用 `firstPartyHostsTracing` 来配置当前应用的 API 服务域名:
```swift theme={null}
import DatadogRUM
RUM.enable(
with: RUM.Configuration(
applicationID: "",
urlSessionTracking: RUM.Configuration.URLSessionTracking(
firstPartyHostsTracing: .trace(
hosts: [
"api.example.com",
"example.com"
],
sampleRate: 20
)
)
)
)
URLSessionInstrumentation.enable(
with: .init(
delegateClass: SessionDelegate.self
)
)
```
```objective-c theme={null}
@import DatadogObjc;
DDRUMConfiguration *configuration = [[DDRUMConfiguration alloc] initWithApplicationID:@""];
DDURLSessionTracking *urlSessionTracking = [DDURLSessionTracking new];
[urlSessionTracking setFirstPartyHostsTracing:[DDRUMFirstPartyHostsTracing alloc] initWithHosts:@[@"api.example.com", @"example.com"] sampleRate:20];
configuration.urlSessionTracking = urlSessionTracking;
[RUM enableWith:configuration];
[DDURLSessionInstrumentation enableWithConfiguration:[DDURLSessionInstrumentationConfiguration alloc] initWithDelegateClass:[SessionDelegate class]]];
```
**参数说明:**
* `hosts`: 需要追踪的域名列表
* `sampleRate`: 要追踪的请求百分比(0-100),默认 100
### 如何关联
分布式追踪协议通过在 HTTP Header 上添加对应的头部字段(`traceparent`、`tracestate`)实现,以下是对相应 header 的说明:
```
traceparent: [version]-[trace id]-[parent id]-[trace flags]
```
* `version`: 当前为 `00`
* `trace id`: 128 bits 的 trace ID 通过 16 进制处理后变成 32 个字符
* `parent id`: 64 bits 的 span ID,16 进制处理后为 16 个字符
* `trace flags`: 代表是否有降采样,`01` 代表命中采样,`00` 代表非采样
```
tracestate: dd=s:[sampling priority];o:[origin]
```
* `sampling priority`: `1` 代表 trace 被采样
* `origin`: 始终为 `rum`,代表通过 RUM SDK 采集
**示例:**
```
traceparent: 00-00000000000000008448eb211c80319c-b7ad6b7169203331-01
tracestate: dd=s:1;o:rum
```
### 如何验证
添加配置后,可在 Xcode 的网络调试工具或代理工具(如 Charles、Proxyman)中查看从应用中发送的请求,如能正确携带对应的 header 则说明配置无误。
## 最佳实践
确保正确配置 `applicationID` 和 `clientToken`,以避免数据上传失败。
根据应用需求调整采样率和隐私设置,平衡数据量与合规性。
事件映射器中修改的属性应遵循允许修改的属性列表,避免修改保留属性。
对于复杂的视图追踪场景,建议实现自定义的 `ViewsPredicate`。
## 相关文档
了解如何集成 iOS SDK
了解 SDK 收集的数据类型
了解 SDK 兼容性要求
# iOS SDK 兼容性
Source: https://docs.flashduty.com/zh/rum/sdk/ios/compatible
了解 iOS RUM SDK 支持的平台版本、开发工具、UI 框架和网络库兼容性
本文档说明 iOS RUM SDK 支持的操作系统版本、开发平台、UI 框架及第三方库兼容性。
## 系统要求
iOS RUM SDK 支持以下操作系统版本:
| 平台 | 支持状态 | 最低版本 | 说明 |
| ----------------------------- | ------- | ------ | ------------------ |
| **iOS** | ✅ 完全支持 | 12.0+ | 推荐平台,所有功能完整支持 |
| **iPadOS** | ✅ 完全支持 | 12.0+ | 所有功能完整支持 |
| **tvOS** | ✅ 完全支持 | 12.0+ | 所有功能完整支持 |
| **macOS (Designed for iPad)** | ✅ 支持 | 11.0+ | iPad 应用运行在 macOS 上 |
| **macOS (Catalyst)** | ⚠️ 部分支持 | 10.14+ | 支持构建,运行时某些功能可能受限 |
| **macOS** | ⚠️ 部分支持 | 10.14+ | 非官方支持,某些功能可能无法正常工作 |
| **visionOS** | ⚠️ 部分支持 | 1.0+ | 非官方支持,某些功能可能无法正常工作 |
| **watchOS** | ❌ 不支持 | - | 目前不支持 watchOS 平台 |
## 开发工具链
### Xcode
SDK 使用最新版本的 Xcode 构建,但始终向后兼容 App Store 提交所需的最低支持 Xcode 版本。
**推荐版本:** Xcode 14.0 及以上
### 依赖管理工具
| 工具 | 支持状态 | 推荐程度 |
| ------------------------- | ------ | ------ |
| **Swift Package Manager** | ✅ 完全支持 | 推荐使用 ⭐ |
| CocoaPods | 🚧 计划中 | 即将支持 |
| Carthage | 🚧 计划中 | 即将支持 |
### 编程语言
| 语言 | 最低版本 | 支持状态 |
| --------------- | ---- | ---------- |
| **Swift** | 5.0+ | ✅ 完全支持(推荐) |
| **Objective-C** | 2.0 | ✅ 完全支持 |
## 框架兼容性
| 框架 | 自动追踪 | 手动追踪 | 说明 |
| ----------- | ---- | ---- | --------------------------------------------------- |
| **UIKit** | ✅ | ✅ | 支持自动追踪 UIViewController 和用户交互 |
| **SwiftUI** | ⚠️ | ✅ | 需要使用 `.trackRUMView()` 和 `.trackRUMTapAction()` 修饰符 |
UIKit 应用可以完全自动追踪,SwiftUI 应用需要添加修饰符。
| 框架/库 | 自动追踪 | 手动追踪 | 说明 |
| ------------------ | ---- | ---- | -------------------------------- |
| **URLSession** | ✅ | ✅ | 需要启用 `URLSessionInstrumentation` |
| **Alamofire** | ❌ | ✅ | 可通过自定义拦截器手动追踪 |
| **Apollo GraphQL** | ❌ | ✅ | 可通过自定义拦截器手动追踪 |
| **AFNetworking** | ❌ | ⚠️ | 已废弃,建议迁移到 URLSession |
推荐使用 URLSession,可以实现完全自动的网络请求追踪。
| 类型 | 支持状态 | 说明 |
| ------------- | ------ | ------------------------- |
| **WKWebView** | ✅ 完全支持 | 需要集成 `FlashcatWebView` 模块 |
| **UIWebView** | ❌ 不支持 | 已被 Apple 弃用 |
UIWebView 已被 Apple 废弃,请使用 WKWebView。
## SDK 模块
Flashduty iOS SDK 由以下模块组成:
| 依赖名称 (SPM/CocoaPods) | Import 名称 | 功能说明 | 是否必需 |
| --------------------------- | ------------------------ | ------------- | ---- |
| **FlashcatCore** | `DatadogCore` | 核心 SDK,提供基础功能 | ✅ 必需 |
| **FlashcatRUM** | `DatadogRUM` | RUM 数据收集和上报 | ✅ 必需 |
| **FlashcatWebViewTracking** | `DatadogWebViewTracking` | WebView 集成支持 | 可选 |
| **FlashcatCrashReporting** | `DatadogCrashReporting` | 崩溃报告 | 推荐 |
根据您的需求选择性集成模块,只有 `FlashcatCore` 和 `FlashcatRUM` 是必需的。
## 第三方依赖
Flashduty iOS SDK 依赖以下第三方库:
| 库名称 | 版本 | 用途 |
| --------------- | ------ | ------ |
| PLCrashReporter | 1.12.0 | 崩溃报告收集 |
## 已知限制
* SwiftUI 视图需要手动添加 `.trackRUMView()` 修饰符才能被追踪
* 在 `List` 内使用 `.trackRUMTapAction()` 可能会影响默认手势行为
* 对于 `List` 元素,建议使用自定义操作 API
SwiftUI 应用建议结合自动追踪和手动追踪,以获得最佳监控效果。
**非官方支持平台:**
* macOS 和 visionOS 不是官方支持的平台
* 某些依赖 UIKit 的功能在这些平台上可能无法正常工作
* 不保证未来版本的兼容性
* Catalyst 模式仅支持构建,运行时某些功能可能受限
* 建议在实际使用前进行充分测试
如果您的应用主要面向 macOS Catalyst,建议先在测试环境中验证所有功能。
## 最低部署要求
**必要条件:**
* 最低操作系统版本:iOS 12.0 / iPadOS 12.0 / tvOS 12.0
* 最低 Xcode 版本:Xcode 14.0
* 最低 Swift 版本:Swift 5.0
* 网络权限:应用需要有网络访问权限以上报数据
* 存储空间:SDK 需要少量本地存储空间用于缓存离线数据
## 性能影响
Flashduty iOS SDK 设计为轻量级,对应用性能的影响极小:
| 指标 | 影响 |
| ---------- | ------------------ |
| **CPU 占用** | \< 1% |
| **内存占用** | \< 10 MB |
| **包大小增加** | 约 2-3 MB(视集成的模块而定) |
| **启动时间影响** | \< 100ms |
SDK 使用异步批处理机制,不会阻塞主线程,对用户体验影响微乎其微。
## 版本更新策略
SDK 遵循语义化版本控制(Semantic Versioning):
| 更新类型 | 版本格式 | 兼容性 | 说明 |
| -------- | ------ | ----- | ---------------- |
| **主版本** | v3.0.0 | 可能不兼容 | 可能包含破坏性更改,需要代码调整 |
| **次版本** | v3.1.0 | 向后兼容 | 新增功能,保持向后兼容 |
| **补丁版本** | v3.1.1 | 完全兼容 | Bug 修复,完全向后兼容 |
建议定期更新 SDK 到最新稳定版本以获得最佳性能和安全性。
## 相关文档
了解如何集成 iOS SDK
配置 SDK 的高级功能
了解 SDK 收集的数据类型
# iOS SDK 数据收集
Source: https://docs.flashduty.com/zh/rum/sdk/ios/data-collection
全面了解 Flashduty iOS RUM SDK 自动收集的性能指标、事件属性和设备信息
iOS RUM SDK 会自动生成包含相关指标和属性的事件。每个 RUM 事件都包含默认属性(如 `view.url`、`device.type`、`geo.country`)以及事件特定的指标和属性(如 `view.time_spent`、`resource.method`)。
## 应用启动指标
在应用启动期间,iOS SDK 会自动记录应用启动时间并创建相应的视图。
启动时间测量从进程启动到第一个 `applicationDidBecomeActive` 通知之间的时间间隔。
| 属性 | 类型 | 描述 |
| --------------------- | ------ | -------------------------------- |
| `view.is_start_view` | 布尔值 | 标识该视图是否为应用启动时创建的初始视图 |
| `action.type` | 字符串 | 应用启动操作的类型,值为 `application_start` |
| `action.loading_time` | 数字(纳秒) | 应用启动所需的时间 |
## 视图监测
在 iOS 应用中,视图会在用户访问不同屏幕时自动创建。当用户打开屏幕时,视图开始记录;当视图不再可见时停止。
**视图生命周期管理:**
* 视图停止时不会立即结束,而是保持在 `inactive` 状态一段时间
* 如果在此期间启动了新视图,之前的视图将完全结束
* 如果没有新视图启动,之前的视图将恢复为 `active` 状态
**后台行为:**
* 当应用进入后台时,SDK 会保留最后一个活动视图并监控后台事件
* 后台时间不会计入活动视图的 `time_spent` 指标
* 如果用户立即返回应用,SDK 会恢复原始的 `time_spent` 测量
## 默认属性
iOS RUM SDK 为所有事件自动附加默认属性,帮助您了解用户设备、网络状态和应用上下文。
| 属性 | 类型 | 描述 |
| ---------------- | --- | ----------------------------------------------------- |
| `date` | 整数 | 事件的时间戳(毫秒) |
| `type` | 字符串 | 事件的类型(如 `session`、`view`、`resource`、`error`、`action`) |
| `service` | 字符串 | 生成此事件的服务名称 |
| `application.id` | 字符串 | 应用的唯一标识符 |
以下设备相关属性会自动附加到所有事件上:
| 属性 | 类型 | 描述 |
| -------------- | --- | ------------------------------------------------ |
| `device.type` | 字符串 | 设备类型(如 `Mobile`、`Tablet`、`TV`、`Desktop`、`Other`) |
| `device.brand` | 字符串 | 设备品牌,iOS 设备为 `Apple` |
| `device.model` | 字符串 | 设备型号(如 `iPhone`、`iPad`、`iPod Touch`、`Apple TV`) |
| `device.name` | 字符串 | 设备的名称 |
以下操作系统相关属性会自动附加到所有事件上:
| 属性 | 类型 | 描述 |
| ------------------ | --- | ------------------------------- |
| `os.name` | 字符串 | 操作系统名称(如 `iOS`、`iPadOS`、`tvOS`) |
| `os.version` | 字符串 | 操作系统版本号(如 `15.4.1`、`16.0`) |
| `os.version_major` | 字符串 | 操作系统主版本号(如 `15`、`16`) |
以下网络相关属性会自动附加到资源和错误事件上:
| 属性 | 类型 | 描述 |
| ------------------------------------ | ----- | ----------------------------------------- |
| `connectivity.status` | 字符串 | 设备网络连接状态(如 `connected`、`not_connected`) |
| `connectivity.interfaces` | 字符串数组 | 可用的网络接口类型(如 `wifi`、`cellular`、`ethernet`) |
| `connectivity.cellular.technology` | 字符串 | 蜂窝网络技术类型(如 `3G`、`4G`、`LTE`、`5G`) |
| `connectivity.cellular.carrier_name` | 字符串 | 蜂窝网络运营商名称 |
以下属性与 IP 地址的地理位置相关:
| 属性 | 类型 | 描述 |
| ------------------------- | --- | ----------------------- |
| `geo.country` | 字符串 | 国家名称 |
| `geo.country_iso_code` | 字符串 | 国家的 ISO 代码(如 `US`、`CN`) |
| `geo.country_subdivision` | 字符串 | 国家的一级行政区划(如美国的州、中国的省) |
| `geo.continent_code` | 字符串 | 洲的 ISO 代码(如 `EU`、`AS`) |
| `geo.continent` | 字符串 | 洲名称 |
| `geo.city` | 字符串 | 城市名称 |
地理位置信息由 Flashduty 后端根据客户端 IP 地址推断,不会在客户端收集精确的 GPS 位置。
您可以在所有 RUM 事件上启用用户追踪,以关联用户会话并简化问题排查。
| 属性 | 类型 | 描述 |
| ------------------ | --- | ----------------------- |
| `usr.id` | 字符串 | 用户的唯一标识符 |
| `usr.name` | 字符串 | 用户友好名称,默认显示在 RUM UI 中 |
| `usr.email` | 字符串 | 用户电子邮件地址,如果没有用户名则显示电子邮件 |
| `usr.anonymous_id` | 字符串 | 匿名用户标识符 |
用户属性是可选的,但建议至少提供一个。详见 [追踪用户信息](/zh/rum/sdk/ios/sdk-integration#追踪用户信息)。
当前仅支持以上用户标准字段,其他用户属性不支持。如有需求,可以在 `context` 字段进行配置。
## 事件特定属性
不同的事件类型具有特定的属性和指标。
| 属性 | 类型 | 描述 |
| --------------------------- | --- | --------------------------- |
| `session.id` | 字符串 | 会话的唯一标识符。 |
| `session.type` | 字符串 | 会话类型(如 `user`、`synthetic`)。 |
| `session.is_active` | 布尔值 | 会话是否处于活动状态。 |
| `session.initial_view.id` | 字符串 | 会话中初始视图的 ID。 |
| `session.initial_view.url` | 字符串 | 会话中初始视图的 URL。 |
| `session.initial_view.name` | 字符串 | 会话中初始视图的名称。 |
| `session.last_view.id` | 字符串 | 会话中最后一个视图的 ID。 |
| `session.last_view.url` | 字符串 | 会话中最后一个视图的 URL。 |
| `session.last_view.name` | 字符串 | 会话中最后一个视图的名称。 |
| `session.has_crash` | 布尔值 | 会话是否包含崩溃事件 |
| `session.has_replay` | 布尔值 | 会话是否启用了会话重放 |
| 属性 | 类型 | 描述 |
| --------------------------- | ------ | ------------------------------- |
| `view.id` | 字符串 | 视图的唯一标识符。 |
| `view.url` | 字符串 | 视图的 URL,对应 UIViewController 类名。 |
| `view.name` | 字符串 | 视图的可自定义名称。 |
| `view.referrer` | 字符串 | 前一个视图的 URL。 |
| `view.action.count` | 数字 | 该视图中收集的用户操作数。 |
| `view.error.count` | 数字 | 该视图中收集的错误数。 |
| `view.resource.count` | 数字 | 该视图中收集的资源数。 |
| `view.time_spent` | 数字(纳秒) | 用户在该视图上花费的时间。 |
| `view.network_settled_time` | 数字(纳秒) | 视图启动时完全初始化所需的时间。 |
| `view.is_active` | 布尔值 | 视图是否处于活动状态。 |
| `view.is_slow_rendered` | 布尔值 | 视图渲染是否缓慢。 |
| `view.crash.count` | 数字 | 该视图中发生的崩溃数。 |
| `view.frozen_frame.count` | 数字 | 该视图中的冻结帧数。 |
| `view.refresh_rate_average` | 数字 | 视图的平均刷新率。 |
| `view.refresh_rate_min` | 数字 | 视图的最低刷新率。 |
| `view.memory_average` | 数字 | 视图的平均内存使用量。 |
| `view.memory_max` | 数字 | 视图的最大内存使用量。 |
| `view.cpu_ticks_count` | 数字 | 视图的 CPU 时钟周期数 |
| `view.cpu_ticks_per_second` | 数字 | 视图每秒的 CPU 时钟周期数 |
| 属性 | 类型 | 描述 |
| ------------------------------ | ------ | ------------------------------------------------- |
| `resource.id` | 字符串 | 资源的唯一标识符。 |
| `resource.url` | 字符串 | 资源 URL。 |
| `resource.method` | 字符串 | HTTP 方法(如 `GET`、`POST`、`PATCH`、`DELETE`)。 |
| `resource.type` | 字符串 | 资源类型(如 `xhr`、`image`、`font`、`css`、`js`)。 |
| `resource.status_code` | 数字 | HTTP 响应状态码。 |
| `resource.size` | 数字(字节) | 资源大小。 |
| `resource.duration` | 数字(纳秒) | 加载资源所需的总时间。 |
| `resource.connect.duration` | 数字(纳秒) | 建立服务器连接所需的时间(connectEnd - connectStart)。 |
| `resource.ssl.duration` | 数字(纳秒) | TLS 握手所需的时间。 |
| `resource.dns.duration` | 数字(纳秒) | DNS 解析所需的时间(domainLookupEnd - domainLookupStart)。 |
| `resource.first_byte.duration` | 数字(纳秒) | 等待接收响应首字节的时间(responseStart - requestStart)。 |
| `resource.download.duration` | 数字(纳秒) | 下载响应的时间(responseEnd - responseStart)。 |
| `resource.redirect.duration` | 数字(纳秒) | 后续 HTTP 请求所需的时间(redirectEnd - redirectStart)。 |
| `resource.provider.name` | 字符串 | 资源提供者名称,默认为 `unknown`。 |
| `resource.provider.domain` | 字符串 | 资源提供者域名 |
| `resource.provider.type` | 字符串 | 资源提供者类型(如 `first-party`、`cdn`、`ad`、`analytics`) |
错误事件收集异常和崩溃信息,错误消息和堆栈跟踪会被自动包含:
| 属性 | 类型 | 描述 |
| ----------------- | ------ | ------------------------------------------------------------------------------------------------ |
| `error.source` | 字符串 | 错误来源(如 `webview`、`logger`、`network`)。 |
| `error.type` | 字符串 | 错误类型(在某些情况下为错误代码)。 |
| `error.message` | 字符串 | 简洁、易读的单行错误消息。 |
| `error.stack` | 字符串 | 错误的堆栈跟踪或补充信息。 |
| `error.issue_id` | 字符串 | 错误问题的唯一标识符。 |
| `error.category` | 字符串 | 错误类型的高级分组。可能的值包括:`ANR`、`App Hang`、`Exception`、`Watchdog Termination`、`Memory Warning`、`Network`。 |
| `error.file` | 字符串 | 错误追踪发现问题的文件。 |
| `error.is_crash` | 布尔值 | 该错误是否导致应用崩溃 |
| `freeze.duration` | 数字(纳秒) | 主线程冻结的持续时间(仅适用于 App Hang) |
**网络错误:**
网络错误包含有关失败 HTTP 请求的信息,额外收集以下属性:
| 属性 | 类型 | 描述 |
| -------------------------------- | --- | ----------------------------------------------- |
| `error.resource.status_code` | 数字 | HTTP 响应状态码。 |
| `error.resource.method` | 字符串 | HTTP 方法(如 `GET`、`POST`)。 |
| `error.resource.url` | 字符串 | 资源 URL。 |
| `error.resource.provider.name` | 字符串 | 资源提供者名称,默认为 `unknown`。 |
| `error.resource.provider.domain` | 字符串 | 资源提供者域名 |
| `error.resource.provider.type` | 字符串 | 资源提供者类型(如 `first-party`、`cdn`、`ad`、`analytics`) |
| 属性 | 类型 | 描述 |
| ------------------------ | ------ | ------------------------------------ |
| `action.id` | 字符串 | 用户操作的唯一标识符。 |
| `action.type` | 字符串 | 用户操作类型(如 `tap`、`application_start`)。 |
| `action.name` | 字符串 | 用户操作的名称。 |
| `action.target.name` | 字符串 | 用户交互的元素(仅适用于自动收集的操作) |
| `action.loading_time` | 数字(纳秒) | 操作的加载时间 |
| `action.resource.count` | 数字 | 该操作触发的资源数 |
| `action.error.count` | 数字 | 该操作触发的错误数 |
| `action.long_task.count` | 数字 | 该操作触发的长任务数 |
当应用发生崩溃时,会收集以下额外属性:
| 属性 | 类型 | 描述 |
| --------------------- | --- | -------------------------------- |
| `error.signal` | 字符串 | 导致崩溃的信号名称(如 `SIGABRT`、`SIGSEGV`) |
| `error.binary_images` | 数组 | 崩溃时加载的二进制映像列表 |
| `error.threads` | 数组 | 崩溃时所有线程的状态 |
| `error.meta` | 对象 | 崩溃相关的元数据 |
## 数据存储与安全
### 本地存储机制
在上传到 Flashduty 之前,数据以明文形式存储在应用沙盒的缓存目录(`Library/Caches`)中。
**安全保护:**
* 缓存目录受 iOS 应用沙盒保护
* 设备上安装的其他应用无法读取此目录
### 数据管理策略
为确保 SDK 不会占用过多磁盘空间,SDK 会自动管理本地数据:
| 策略 | 说明 |
| -------- | ------------------------- |
| **智能上传** | 当网络可用且设备电量充足时,数据以批次形式发送 |
| **失败重试** | 如果网络不可用或上传失败,批次会被保留直到成功发送 |
| **自动清理** | 超过一定时限的数据会被自动清理 |
即使用户在离线时使用应用,数据也会被保留并在网络恢复后上传,不会丢失任何监控数据。
## 相关文档
了解如何集成 iOS SDK
配置自定义属性、采样和事件过滤
了解 SDK 兼容性要求
# iOS SDK 性能影响
Source: https://docs.flashduty.com/zh/rum/sdk/ios/performance-impact
了解 Flashduty iOS RUM SDK 对应用 CPU、内存、启动时间、包大小和网络使用的影响,以及性能优化建议。
## 概述
在将任何 SDK 集成到 iOS 应用时,了解其性能影响对于维护良好的用户体验至关重要。Flashduty RUM SDK 在设计时以最小化性能开销为目标,并提供透明的测量数据,帮助您评估 SDK 是否符合应用的性能预算。
SDK 采用异步处理机制,所有数据处理都在后台队列中进行,不会阻塞主线程。
## 性能基准测试
为了评估 SDK 对应用性能的实际影响,我们在典型使用场景下进行了性能基准测试。测试中启用了以下 SDK 功能:
* 基础 RUM 监控:视图、操作、资源追踪
* 链路追踪
SDK 使用默认配置进行初始化,并模拟常见用户操作(如页面浏览、滚动列表、网络请求等)。
### 测试结果
| 指标 | 集成 SDK 后 | 未集成 SDK | 影响 |
| ---------- | ---------------------- | --------- | -------- |
| 峰值 CPU 使用率 | \~44% | \~40% | +4% |
| 峰值内存使用 | \~72 MB | \~68 MB | +4 MB |
| 应用启动时间 | \~0.9 ms | \~0.65 ms | +0.25 ms |
| 包大小 | +1.4 MB | - | 约 1.4 MB |
| 网络使用 | \~22 KB 发送 / \~2 KB 接收 | - | 根据事件量变化 |
以上数据为典型场景下的参考值,实际影响会因应用复杂度、设备性能和 SDK 配置不同而有所差异。
### 性能影响详解
SDK 对 CPU 的影响主要来自:
* 事件收集和处理
* 数据批处理和压缩
* 网络请求上报
SDK 采用异步处理机制,所有数据处理都在后台队列中进行,不会阻塞主线程,确保不影响应用的 UI 响应性能。
SDK 使用固定大小的内存缓冲区存储待上报的事件数据,不会随时间无限增长。过旧的数据会被自动清理,确保不会占用过多内存。
SDK 初始化过程经过优化,对应用启动时间的影响控制在亚毫秒级。
建议在 `AppDelegate` 的 `didFinishLaunchingWithOptions` 中尽早初始化 SDK,以便捕获完整的应用启动过程。
SDK 采用模块化设计,您可以根据需要只引入必要的功能模块:
| 依赖名称 | Import 名称 | 说明 |
| ------------------------- | ------------------------ | ---------- |
| `FlashcatCore` | `DatadogCore` | 核心功能(必需) |
| `FlashcatRUM` | `DatadogRUM` | RUM 监控 |
| `FlashcatTrace` | `DatadogTrace` | 链路追踪 |
| `FlashcatWebViewTracking` | `DatadogWebViewTracking` | WebView 追踪 |
只引入必要的模块可以最小化对包大小的影响。
SDK 采用以下策略优化网络使用:
* **批量上报**:事件先缓存到本地,批量发送以减少网络请求次数
* **数据压缩**:上报数据经过压缩处理,减少传输流量
* **智能调度**:根据网络状态和电量情况智能调度上报时机
## 性能优化建议
如果您对性能有特殊要求,可以考虑以下优化措施:
通过配置采样率减少收集的事件数量:
```swift theme={null}
RUM.enable(
with: RUM.Configuration(
applicationID: "",
sessionSampleRate: 80 // 采样 80% 的会话
)
)
```
只启用必要的追踪功能:
```swift theme={null}
RUM.enable(
with: RUM.Configuration(
applicationID: "",
uiKitViewsPredicate: nil, // 禁用自动视图追踪
uiKitActionsPredicate: nil // 禁用自动操作追踪
)
)
```
如果不需要追踪后台事件:
```swift theme={null}
RUM.enable(
with: RUM.Configuration(
applicationID: "",
trackBackgroundEvents: false
)
)
```
## 离线数据存储
SDK 在设备离线时会将数据存储到本地,存储空间使用受到严格限制:
* 使用固定大小的磁盘缓存
* 过期数据自动清理
* 不会因缓存数据过多影响设备存储空间
## 电池消耗
SDK 在设计时充分考虑了电池消耗:
* 在电量低于特定阈值时自动降低上报频率
* 利用系统的后台任务机制进行数据上报
* 避免频繁唤醒设备
## 相关文档
了解如何接入 SDK
了解如何配置 SDK 的高级功能
了解 SDK 收集的数据类型
了解 SDK 支持的平台版本
# iOS SDK 接入
Source: https://docs.flashduty.com/zh/rum/sdk/ios/sdk-integration
快速集成 iOS RUM SDK,实时监控应用性能、错误和用户行为
Flashduty iOS RUM SDK 支持 **iOS 12.0、iPadOS 12.0、tvOS 12.0** 及以上版本。通过集成 SDK,您可以实时监控 iOS 应用的性能、错误和用户行为。
**关于依赖和包名的说明**
Flashduty iOS SDK 完全兼容 Datadog 开源协议。在 Swift Package Manager 或 CocoaPods 中添加依赖时使用 `FlashcatCore`、`FlashcatRUM`、`FlashcatTrace` 等名称,但在代码中 import 时使用 `DatadogCore`、`DatadogRUM`、`DatadogTrace` 等模块名。您可以无缝复用 Datadog 生态的文档、示例和最佳实践,同时享受 Flashduty 平台的服务。
## 接入步骤
Flashduty iOS SDK 支持 Swift Package Manager 和 CocoaPods 两种安装方式:
1. 在 Xcode 中,打开您的项目,选择 **File > Add Package Dependencies**
2. 在搜索栏中输入 Flashduty SDK 的 Git 仓库 URL:
```
https://github.com/flashcatcloud/fc-sdk-ios
```
3. 选择版本规则:
* **推荐**:选择 **Up to Next Major Version**,并输入当前最新版本号(如 `0.3.0`)
* 这样可以在保持兼容性的同时获取 bug 修复和小版本更新
4. 点击 **Add Package**,等待 Xcode 下载依赖
5. 在弹出的 **Choose Package Products** 窗口中,选择需要添加到 Target 的模块:
* `FlashcatCore` - 核心 SDK(必选)
* `FlashcatRUM` - RUM 功能模块(必选)
* `FlashcatTrace` - Trace 功能模块(启用 Trace feature、自动 Trace span 或手动 span 时需要)
* `FlashcatWebViewTracking` - WebView 追踪(可选)
* `FlashcatCrashReporting` - 崩溃报告(推荐)
6. 确保每个模块都关联到正确的 Target,点击 **Add Package** 完成添加
在项目的 `Podfile` 中添加以下依赖:
```ruby Podfile theme={null}
pod 'FlashcatCore', '~> 0.3.0' # 核心 SDK(必选)
pod 'FlashcatRUM', '~> 0.3.0' # RUM 功能(必选)
pod 'FlashcatTrace', '~> 0.3.0' # Trace 功能(启用 Trace feature 或手动 span 时需要)
# 可选模块
pod 'FlashcatWebViewTracking', '~> 0.3.0' # WebView 追踪
pod 'FlashcatCrashReporting', '~> 0.3.0' # 崩溃报告
```
然后执行 `pod install`,并使用 `.xcworkspace` 文件打开项目。
**获取最新版本号**
查看 [SDK 版本发布页面](https://github.com/flashcatcloud/fc-sdk-ios/releases) 获取最新稳定版本。建议固定到具体版本号,避免意外更新。
在 Flashduty 控制台的 [应用管理](https://console.flashcat.cloud/rum/apps) 页面:
1. 创建或选择一个 iOS 应用
2. 获取以下凭证信息:
* **Application ID** - 应用唯一标识符
* **Client Token** - 客户端访问令牌
在您的 `AppDelegate.swift` 的 `application(_:didFinishLaunchingWithOptions:)` 方法中初始化 SDK:
```swift AppDelegate.swift theme={null}
import UIKit
import DatadogCore
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
Datadog.initialize(
with: Datadog.Configuration(
clientToken: "",
env: ""
),
trackingConsent: .granted
)
return true
}
}
```
**参数说明:**
* `clientToken` - 从控制台获取的客户端令牌(必填)
* `env` - 环境名称,如 `production`、`staging`(必填)
* `trackingConsent` - 用户追踪同意状态(详见下方说明)
**TrackingConsent 同意状态:**
| 状态 | 行为 |
| ------------- | ---------------------- |
| `.granted` | 开始收集数据并发送到 Flashduty |
| `.pending` | 开始收集和批处理数据,但不发送,等待后续确认 |
| `.notGranted` | 不收集任何数据 |
您可以在初始化后通过 `Datadog.set(trackingConsent:)` 动态修改追踪同意状态。
配置并启用 RUM 功能。建议在 `AppDelegate` 中尽早启用:
```swift AppDelegate.swift theme={null}
import DatadogRUM
RUM.enable(
with: RUM.Configuration(
applicationID: "",
uiKitViewsPredicate: DefaultUIKitRUMViewsPredicate(),
uiKitActionsPredicate: DefaultUIKitRUMActionsPredicate(),
swiftUIViewsPredicate: DefaultSwiftUIRUMViewsPredicate(),
swiftUIActionsPredicate: DefaultSwiftUIRUMActionsPredicate(
isLegacyDetectionEnabled: true
),
urlSessionTracking: RUM.Configuration.URLSessionTracking()
)
)
```
**配置参数说明:**
* `applicationID` - 从控制台获取的 RUM 应用 ID
* `uiKitViewsPredicate` - UIKit 视图追踪策略
* `uiKitActionsPredicate` - UIKit 用户操作追踪策略
* `swiftUIViewsPredicate` - SwiftUI 视图追踪策略
* `swiftUIActionsPredicate` - SwiftUI 用户操作追踪策略
* `urlSessionTracking` - URLSession 网络请求追踪配置
SDK 将自动开始收集以下数据:
* UIKit 和 SwiftUI 视图追踪
* 用户交互事件
* 网络请求监控
**配置一方域名与 Trace 关联:**
如果需要把移动端 RUM Resource 与后端 Trace 关联,请在 `RUM.Configuration` 中为一方域名配置 `firstPartyHostsTracing`。host 只填写域名,不要包含 `http://`、`https://` 或路径。若您已经在上一步调用 `RUM.enable(...)`,请将下面的 `urlSessionTracking` 合并到同一次 `RUM.Configuration` 中,不要重复启用 RUM。
```swift AppDelegate.swift theme={null}
import DatadogRUM
RUM.enable(
with: RUM.Configuration(
applicationID: "",
uiKitViewsPredicate: DefaultUIKitRUMViewsPredicate(),
urlSessionTracking: RUM.Configuration.URLSessionTracking(
firstPartyHostsTracing: .traceWithHeaders(
hostsWithHeaders: [
"example.com": [.datadog, .tracecontext],
"api.example.com": [.datadog, .tracecontext]
],
sampleRate: 100
)
)
)
)
```
配置 `example.com` 会匹配 `api.example.com` 等子域名。`sampleRate` 取值范围为 `0` 到 `100`,生产环境可按采样策略调低。
**启用 Trace 功能:**
如需采集 Trace span 或使用手动 span API,请在 `Datadog.initialize(...)` 后启用 Trace:
```swift AppDelegate.swift theme={null}
import DatadogTrace
Trace.enable()
```
如需让 Trace feature 自动为 `URLSession` 一方域名请求创建 span,可在 `Trace.Configuration` 中配置相同的一方域名,并用下面的调用替代上面的 `Trace.enable()`:
```swift AppDelegate.swift theme={null}
import DatadogTrace
Trace.enable(
with: Trace.Configuration(
urlSessionTracking: Trace.Configuration.URLSessionTracking(
firstPartyHostsTracing: .traceWithHeaders(
hostsWithHeaders: [
"example.com": [.datadog, .tracecontext],
"api.example.com": [.datadog, .tracecontext]
],
sampleRate: 100
)
)
)
)
```
**启用 URLSession 追踪:**
要监控从 `URLSession` 实例发送的网络请求,需要启用 `URLSessionInstrumentation` 并传入您的 delegate 类型:
```swift theme={null}
import DatadogRUM
URLSessionInstrumentation.enable(
with: .init(
delegateClass: YourSessionDelegate.self
)
)
let session = URLSession(
configuration: .default,
delegate: YourSessionDelegate(),
delegateQueue: nil
)
```
**自动追踪的网络信息:**
* 请求 URL、方法、状态码
* 请求和响应头信息
* 请求时长和数据大小
* 网络错误信息
* 命中一方域名和采样策略时注入的 trace header(如 `x-datadog-*`、`traceparent`、`tracestate`)
只有在视图处于活动状态时发起的网络请求才会被记录为 RUM Resource。后端服务需要接收并继续传递这些 trace header,才能完成前后端链路关联。
## 视图追踪
Flashduty iOS SDK 支持自动追踪 UIKit 和 SwiftUI 视图。
### UIKit 视图自动追踪
UIKit 视图会通过 `DefaultUIKitRUMViewsPredicate` 自动追踪。SDK 会追踪 `UIViewController` 的生命周期,自动记录视图的显示和隐藏。
### SwiftUI 视图追踪
对于 SwiftUI 应用,需要在视图中添加 `.trackRUMView()` 修饰符:
```swift theme={null}
import SwiftUI
import DatadogRUM
struct ProductView: View {
var body: some View {
VStack {
Text("Product Details")
// Your view content
}
.trackRUMView(name: "Product")
}
}
```
`trackRUMView(name:)` 方法会在 SwiftUI 视图出现和消失时自动开始和停止视图追踪。
### 自定义视图追踪
如果需要更精细的控制,可以手动追踪视图:
```swift theme={null}
import DatadogRUM
// 开始追踪视图
RUMMonitor.shared().startView(
key: "view-key",
name: "View Name",
attributes: [:]
)
// 停止追踪视图
RUMMonitor.shared().stopView(
key: "view-key",
attributes: [:]
)
```
## 用户操作追踪
### UIKit 操作自动追踪
UIKit 中的用户操作(如点击按钮、切换开关等)会通过 `DefaultUIKitRUMActionsPredicate` 自动追踪。
### SwiftUI 操作追踪
对于 SwiftUI 控件,可以添加 `.trackRUMTapAction()` 修饰符:
```swift theme={null}
import SwiftUI
import DatadogRUM
struct CheckoutView: View {
var body: some View {
Button("Complete Purchase") {
// Button action
}
.trackRUMTapAction(name: "Purchase")
}
}
```
在 `List` 内使用 `.trackRUMTapAction(name:)` 可能会影响默认手势(例如禁用 `Button` 操作或破坏 `NavigationLink`)。对于 `List` 元素,建议使用自定义操作 API。
### 自定义操作追踪
手动追踪用户操作:
```swift theme={null}
import DatadogRUM
RUMMonitor.shared().addAction(
type: .tap,
name: "Button Tapped",
attributes: ["button_id": "submit"]
)
```
## 高级配置
### 追踪错误
Flashduty iOS SDK 会自动捕获应用崩溃和未捕获的异常。您也可以手动记录错误:
```swift theme={null}
import DatadogRUM
RUMMonitor.shared().addError(
message: "Network request failed",
type: "NetworkError",
source: .network,
attributes: [
"url": "https://api.example.com",
"status_code": 500
]
)
```
所有错误信息都会在控制台的 RUM Explorer 中显示,包括错误堆栈、属性和 JSON 详情。
详细的异常上报配置请参阅 [iOS 异常上报](/zh/rum/error-tracking/erro-reporting/ios)。
### 追踪后台事件
您可以追踪应用在后台运行时的事件(例如崩溃和网络请求):
```swift theme={null}
RUM.enable(
with: RUM.Configuration(
applicationID: "",
trackBackgroundEvents: true
)
)
```
追踪后台事件可能会产生额外的会话,从而影响计费。如有疑问,请联系 Flashduty 支持团队。
### 追踪用户信息
您可以为当前会话设置用户信息,便于追踪特定用户的行为:
```swift theme={null}
import DatadogCore
Datadog.setUserInfo(
id: "user-123",
name: "John Doe",
email: "john.doe@example.com"
)
```
当前仅支持设置用户标准字段:`id`、`name`、`email`、`anonymous_id`;其他用户属性不支持。如有需求,可以在 `context` 字段进行配置。
### 离线数据处理
iOS SDK 确保在用户设备离线时的数据可用性:
**数据持久化机制:**
* 网络信号弱或设备电量过低时,事件以批次形式存储在本地
* 网络恢复后自动上传,确保不丢失数据
* 自动清理过旧数据,避免占用过多磁盘空间
即使用户在离线时使用应用,数据也会被保留并在网络恢复后上传,不会丢失任何监控数据。
## WebView 集成
如果您的 iOS 应用中包含 WKWebView,可以启用 WebView 追踪来监控 Web 内容的性能和错误。
在 Swift Package Manager 添加包依赖时,同时添加 `FlashcatWebViewTracking` 模块。
在您的 ViewController 中启用 WebView 追踪:
```swift theme={null}
import DatadogWebViewTracking
import WebKit
let webView = WKWebView()
// 为指定的 WKWebView 启用追踪
WebViewTracking.enable(
webView: webView,
hosts: ["example.com", "*.example.com"]
)
```
**参数说明:**
* `webView` - 需要追踪的 WKWebView 实例
* `hosts` - 允许追踪的域名列表,支持通配符(如 `*.example.com`)
WebView 中的 Web 页面现在可以与原生应用的 RUM 数据关联起来。
### 禁用自动用户数据收集
为了符合隐私法规或组织数据治理政策,您可以禁用自动收集用户数据。
创建应用后,进入 **应用管理**页面并点击您的应用。
点击 **用户数据收集** 选项,使用开关控制以下设置:
* 客户端 IP 收集
* 地理位置数据收集
## 验证接入
接入完成后,验证集成是否成功:
在 Xcode 控制台中搜索 `Datadog` 关键字,查看 SDK 初始化和数据上报日志。
登录 Flashduty 控制台,进入对应的 RUM 应用,查看是否有数据上报。
在应用中执行以下操作验证数据采集:
* 打开应用的不同页面,验证页面浏览事件
* 执行用户操作(点击、滑动等),验证交互事件
* 触发网络请求,验证资源加载事件
* 手动触发一个错误,验证错误追踪
如果看到数据上报且控制台中有数据显示,说明集成成功!
## 下一步
深入配置 SDK 的高级功能,如自定义采样、用户标识、全局上下文等
了解 SDK 收集的数据类型和数据结构
查看和分析应用的性能、错误和用户行为数据
配置崩溃报告和异常追踪功能
# Web SDK 高级配置
Source: https://docs.flashduty.com/zh/rum/sdk/web/advanced-config
深入了解 Web RUM SDK 的高级配置功能,包括视图管理、数据控制、用户会话和分布式追踪
本文档介绍 Web RUM SDK 的高级配置选项,帮助您根据业务需求定制数据收集行为。
RUM 提供多种高级配置选项:
屏蔽个人身份信息等敏感数据
将用户会话与内部用户标识关联
通过采样降低 RUM 数据收集量
为数据添加丰富的上下文信息
## 覆盖默认 RUM 视图名称
RUM 会在用户访问新页面或 SPA 中 URL 更改时自动生成视图事件。视图名称默认从当前页面 URL 计算,并自动移除变量 ID(包含数字的路径段)。例如,`/dashboard/1234` 和 `/dashboard/9a` 会被归一化为 `/dashboard/?`。
您可以通过设置 `trackViewsManually` 选项手动跟踪视图事件,并为视图指定自定义名称。
### 配置手动跟踪视图
在初始化时设置 `trackViewsManually` 为 `true`:
```javascript rum-init.js theme={null}
import { flashcatRum } from "@flashcatcloud/browser-rum";
flashcatRum.init({
applicationId: "",
clientToken: "",
trackViewsManually: true
});
```
在每个新页面或路由更改时调用 `startView` 方法:
```javascript theme={null}
flashcatRum.startView({
name: "checkout",
service: "purchase",
version: "1.2.3",
context: {
payment: "Done"
}
});
```
视图名称,默认为页面 URL 路径
服务名称,默认为创建 RUM 应用时指定的服务
应用版本,默认为创建 RUM 应用时指定的版本
视图的附加上下文,应用于视图及其子事件
### React Router 集成
```javascript RumTracker.jsx theme={null}
import { matchRoutes, useLocation } from "react-router-dom";
import { routes } from "path/to/routes";
import { flashcatRum } from "@flashcatcloud/browser-rum";
import { useEffect } from "react";
export default function App() {
let location = useLocation();
useEffect(() => {
const routeMatches = matchRoutes(routes, location.pathname);
const viewName = routeMatches && computeViewName(routeMatches);
if (viewName) {
flashcatRum.startView({ name: viewName });
}
}, [location.pathname]);
// ...
}
function computeViewName(routeMatches) {
let viewName = "";
for (let index = 0; index < routeMatches.length; index++) {
const routeMatch = routeMatches[index];
const path = routeMatch.route.path;
if (!path) continue;
if (path.startsWith("/")) {
viewName = path;
} else {
viewName += viewName.endsWith("/") ? path : `/${path}`;
}
}
return viewName || "/";
}
```
### 设置视图名称
使用 `setViewName` 方法更新当前视图的名称,而无需启动新视图:
```javascript theme={null}
flashcatRum.setViewName("Checkout");
```
## 控制首屏 Web Vitals 采集
Web SDK 默认在初始加载视图中采集 Web Vitals 和首屏性能指标,包括 FCP、LCP、FID 和加载时间。这些指标会以页面导航开始时间为基准计算,适用于真实用户直接打开页面的场景。
如果页面会在用户可见前提前加载,例如被浏览器预渲染、在后台标签页打开,或由宿主容器提前初始化,首屏指标可能会从不相关的导航开始时间计算,导致 FCP、LCP 或加载时间异常偏大。你可以在初始化时将 `trackWebVitals` 设置为 `false`,只关闭初始加载视图的 Web Vitals 和首屏性能指标采集。
```javascript rum-init.js theme={null}
import { flashcatRum } from "@flashcatcloud/browser-rum";
flashcatRum.init({
applicationId: "",
clientToken: "",
trackWebVitals: false
});
```
| 参数 | 类型 | 默认值 | 说明 |
| ---------------- | ------- | ------ | ------------------------------------------------------------------------------ |
| `trackWebVitals` | boolean | `true` | 是否采集初始加载视图的 Web Vitals 和首屏性能指标。设置为 `false` 后,SDK 不再为初始加载视图采集 FCP、LCP、FID 和加载时间 |
`trackWebVitals` 只影响初始加载视图的 Web Vitals 和首屏性能指标。资源、长任务、用户行为、错误和后续视图事件仍按其他配置项继续采集。
## 丰富和控制 RUM 数据
通过 `beforeSend` 回调函数,您可以在事件发送到 Flashduty 之前对其进行拦截和修改:
* **丰富事件**:添加额外的上下文属性
* **修改事件**:更改事件内容或屏蔽敏感信息
* **丢弃事件**:选择性地丢弃特定 RUM 事件
### 上下文类型
不同的事件类型对应不同的上下文:
| 事件类型 | 上下文 |
| ---------------- | ------------------------------------------------------ |
| View | `Location` 对象 |
| Action | 触发事件的 `Event` 和处理堆栈 |
| Resource (XHR) | `XMLHttpRequest`、`PerformanceResourceTiming` 和处理堆栈 |
| Resource (Fetch) | `Request`、`Response`、`PerformanceResourceTiming` 和处理堆栈 |
| Resource (Other) | `PerformanceResourceTiming` |
| Error | `Error` 对象 |
| Long Task | `PerformanceLongTaskTiming` |
### 丰富 RUM 事件
为事件添加上下文属性,例如为资源事件添加响应头数据:
```javascript theme={null}
flashcatRum.init({
applicationId: "",
clientToken: "",
beforeSend: (event, context) => {
if (event.type === "resource" && event.resource.type === "fetch") {
event.context.responseHeaders = Object.fromEntries(
context.response.headers
);
}
return true;
}
});
```
### 修改 RUM 事件内容
例如,从视图 URL 中屏蔽电子邮件地址:
```javascript theme={null}
flashcatRum.init({
applicationId: "",
clientToken: "",
beforeSend: (event) => {
event.view.url = event.view.url.replace(/email=[^&]*/, "email=REDACTED");
}
});
```
#### 可修改的属性
| 属性 | 说明 |
| -------------------- | ---------------------- |
| `view.url` | 当前页面的 URL |
| `view.referrer` | 前一个页面的 URL |
| `view.name` | 当前视图名称 |
| `service` | 应用的服务名称 |
| `version` | 应用版本 |
| `action.target.name` | 用户交互的元素(仅限自动收集的操作) |
| `error.message` | 错误消息 |
| `error.stack` | 错误堆栈或补充信息 |
| `error.resource.url` | 触发错误的资源 URL |
| `resource.url` | 资源 URL |
| `context` | 通过上下文 API 或手动生成事件添加的属性 |
### 丢弃 RUM 事件
通过在 `beforeSend` 中返回 `false`,可以丢弃特定 RUM 事件:
```javascript theme={null}
flashcatRum.init({
applicationId: "",
clientToken: "",
beforeSend: (event) => {
if (shouldDiscard(event)) {
return false;
}
}
});
```
视图事件无法被丢弃。
## 用户会话
通过为 RUM 会话添加用户信息,您可以:
* 跟踪特定用户的浏览路径
* 了解哪些用户受错误影响最大
* 监控关键用户的性能
### 用户属性
以下为可选的用户属性,建议至少提供一个:
唯一用户标识符
用户友好名称,默认在 RUM UI 中显示
用户电子邮件,若无名称则显示邮件
### 用户会话 API
```javascript theme={null}
flashcatRum.setUser({
id: "1234",
name: "John Doe",
email: "john@doe.com",
plan: "premium"
});
```
```javascript theme={null}
const user = flashcatRum.getUser();
```
```javascript theme={null}
flashcatRum.setUserProperty("name", "John Doe");
```
```javascript theme={null}
flashcatRum.removeUserProperty("name");
```
```javascript theme={null}
flashcatRum.clearUser();
```
用户会话信息更改后,之后的 RUM 事件将包含更新后的信息。注销(调用 `clearUser`)后,最后一个视图仍保留用户信息,但后续视图和会话级别数据不会。
## 采样
默认情况下,RUM 会收集所有会话的数据。您可以通过 `sessionSampleRate` 参数设置采样率来减少收集的会话数量:
```javascript theme={null}
flashcatRum.init({
applicationId: "",
clientToken: "",
sessionSampleRate: 90 // 采集 90% 的会话
});
```
被采样的会话将不收集任何页面视图及其相关遥测数据。
## 用户跟踪同意
为遵守 GDPR、CCPA 等隐私法规,RUM 允许在初始化时设置用户跟踪同意状态:
| 状态 | 行为 |
| --------------- | -------------------- |
| `"granted"` | 开始收集数据并发送到 Flashduty |
| `"not-granted"` | 不收集任何数据 |
### 示例:处理用户同意
```javascript theme={null}
flashcatRum.init({
applicationId: "",
clientToken: "",
trackingConsent: "not-granted"
});
acceptCookieBannerButton.addEventListener("click", function () {
flashcatRum.setTrackingConsent("granted");
});
```
同意状态不会在标签页间同步或持久化,您需要在初始化或通过 `setTrackingConsent` 提供用户决定。
## 视图上下文
您可以通过以下 API 为当前视图及其子事件添加或修改上下文:
```javascript theme={null}
flashcatRum.startView({
name: "checkout",
context: {
hasPaid: true,
amount: 23.42
}
});
```
```javascript theme={null}
flashcatRum.setViewContextProperty("activity", {
hasPaid: true,
amount: 23.42
});
```
```javascript theme={null}
flashcatRum.setViewContext({
originalUrl: "shopist.io/department/chairs"
});
```
## 错误上下文
在捕获错误时,您可以通过 `dd_context` 属性为错误对象附加本地上下文:
```javascript theme={null}
const error = new Error("Something went wrong");
error.dd_context = { component: "Menu", param: 123 };
throw error;
```
## 全局上下文
全局上下文会附加到所有 RUM 事件上:
```javascript theme={null}
// 添加属性
flashcatRum.setGlobalContextProperty("activity", {
hasPaid: true,
amount: 23.42
});
// 删除属性
flashcatRum.removeGlobalContextProperty("codeVersion");
// 替换全局上下文
flashcatRum.setGlobalContext({
codeVersion: 34
});
// 清除全局上下文
flashcatRum.clearGlobalContext();
// 读取全局上下文
const context = flashcatRum.getGlobalContext();
```
### 上下文生命周期
默认情况下,全局上下文和用户上下文存储在当前页面内存中:
* 页面完全刷新后不会保留
* 不同标签页或窗口间不共享
启用 `storeContextsAcrossPages` 选项可以将上下文存储到 `localStorage`:
```javascript theme={null}
flashcatRum.init({
applicationId: "",
clientToken: "",
storeContextsAcrossPages: true
});
```
* 不建议在上下文中存储个人身份信息,因为 `localStorage` 数据会超出用户会话生命周期
* 与 `trackSessionAcrossSubdomains` 选项不兼容
* `localStorage` 容量限制为 5 MiB
## 微前端支持
RUM 支持微前端架构,通过堆栈跟踪机制识别事件来源。在 `beforeSend` 中根据堆栈信息覆盖 `service` 和 `version` 属性:
```javascript theme={null}
const SERVICE_REGEX = /some-pathname\/(?\w+)\/(?\w+)\//;
flashcatRum.init({
applicationId: "",
clientToken: "",
beforeSend: (event, context) => {
const stack = context?.handlingStack || event?.error?.stack;
const { service, version } = stack?.match(SERVICE_REGEX)?.groups || {};
if (service && version) {
event.service = service;
event.version = version;
}
return true;
}
});
```
以下事件无法归因于特定来源:自动收集的操作事件、非 XHR/Fetch 的资源事件、视图事件、CORS 和 CSP 违规事件。
## 集成 RUM 与分布式追踪
集成 RUM 与分布式追踪,可让您将 Web 应用程序的请求与其对应的后端跟踪关联起来,实现完整的前后端链路追踪。
### 使用方法
使用 `allowedTracingUrls` 参数配置当前应用的 API 服务域名:
```javascript theme={null}
import { flashcatRum } from "@flashcatcloud/browser-rum";
flashcatRum.init({
applicationId: "",
clientToken: "",
service: "",
env: "",
version: "1.0.0",
sessionSampleRate: 100,
allowedTracingUrls: [
"https://api.example.com",
/https:\/\/.*\.my-api-domain\.com/,
(url) => url.startsWith("https://api.example.com")
],
traceSampleRate: 20
});
```
```html theme={null}
```
```html theme={null}
```
`allowedTracingUrls` 匹配完整 URL,接受以下类型:
| 类型 | 说明 |
| ------------ | -------------------------- |
| **String** | 匹配任何以该值开头的 URL |
| **RegExp** | 使用正则表达式的 `test()` 方法检查匹配 |
| **Function** | 接收 URL 作为参数,返回 `true` 表示匹配 |
### 追踪协议
分布式追踪通过在 Header 上添加对应的头部字段实现:
**traceparent**: `[version]-[trace id]-[parent id]-[trace flags]`
* `version`: 当前为 00
* `trace id`: 128 bits 的 trace ID,16 进制处理后为 32 个字符
* `parent id`: 64 bits 的 span ID,16 进制处理后为 16 个字符
* `trace flags`: 代表是否有降采样,01 代表命中采样,00 代表非采样
**tracestate**: `dd=s:[sampling priority];o:[origin]`
* `sampling priority`: 1 代表 trace 被采样
* `origin`: 始终为 RUM,代表通过 RUM SDK 采集
**示例**:
```
traceparent: 00-00000000000000008448eb211c80319c-b7ad6b7169203331-01
tracestate: dd=s:1;o:rum
```
### 如何验证
添加配置后,查看从应用中发送的请求,如能正确携带对应的 header 则说明配置无误。
如您的 HTTP 请求涉及到跨域问题,需要确保请求可通过跨域检测。请确保对应的 server [有跨域相关配置](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Allow-Headers),支持[预检请求](https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request)访问。
## 注意事项
* 确保正确配置 `applicationId` 和 `clientToken`,以避免数据上传失败
* 根据应用需求调整采样率和隐私设置,平衡数据量与合规性
* 对于微前端或复杂前端框架,建议在框架路由级别实现 `startView` 逻辑
## 相关文档
了解如何快速接入 RUM SDK
了解 SDK 收集的数据类型和属性
解决常见问题和调试技巧
有关 RUM SDK 的更多详细信息,请访问 [Flashduty SDK GitHub 仓库](https://github.com/flashcatcloud/browser-sdk)。
# Web SDK 兼容性
Source: https://docs.flashduty.com/zh/rum/sdk/web/compatible
Web RUM SDK 支持的浏览器版本、框架和功能兼容性详细说明
本文档详细说明 Web RUM SDK 支持的浏览器、框架、打包工具以及相关限制,帮助您评估 SDK 在目标环境中的适用性。
## 支持的浏览器
| 浏览器 | 桌面端 | 移动端 | 最低版本 | 备注 |
| ----------------- | --- | --- | ----- | -------------- |
| Chrome | ✅ | ✅ | 63+ | 完整支持所有功能 |
| Firefox | ✅ | - | 67+ | 部分功能受限(见下方) |
| Safari | ✅ | ✅ | 12.1+ | 部分功能受限(见下方) |
| Edge | ✅ | - | 79+ | 基于 Chromium 版本 |
| Opera | ✅ | - | 50+ | 完整支持所有功能 |
| Internet Explorer | ❌ | - | - | 不支持 |
不支持 Internet Explorer 11 及更早版本。
## 浏览器功能兼容性
下表详细说明了各浏览器对 SDK 功能的支持情况:
| 功能 | Chrome | Firefox | Safari | Edge | Chrome Android | Safari iOS | Opera |
| ------------ | ------ | ------- | ------ | ---- | -------------- | ---------- | ----- |
| SDK 加载 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| SDK 初始化 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| RUM 数据上报 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 页面隐藏时刷新 | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
| 控制台错误捕获 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 运行时错误捕获 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| CSP 违规检测 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 浏览器干预检测 | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ |
| 自动操作追踪 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 自定义操作追踪 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 长任务检测 | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ |
| 分布式追踪 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 路由变化追踪 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 页面加载时间 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 资源性能监控 | ✅ | ✅ | ⚠️ (1) | ✅ | ✅ | ⚠️ (1) | ✅ |
| 导航性能监控 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Web Vitals | ✅ | ⚠️ (2) | ⚠️ (2) | ✅ | ✅ | ⚠️ (2) | ✅ |
| FCP (首次内容绘制) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
**说明**:
1. 资源大小信息不可用
2. 仅支持 FID(首次输入延迟)指标
## 框架兼容性
### JavaScript 框架
支持 React 16.8+(Hooks),自动追踪 ✅
支持 Vue 2.x 和 Vue 3.x,自动追踪 ✅
支持 Angular 12+,自动追踪 ✅
支持 SSR 和客户端渲染,自动追踪 ✅
支持 SSR 和客户端渲染,自动追踪 ✅
需要额外配置自动追踪 ⚠️
原生 JavaScript(Vanilla JS)完全支持手动追踪功能。
### 打包工具
| 工具 | 支持状态 | 备注 |
| --------- | ---- | ------------------ |
| Webpack | ✅ | 支持所有主流版本(4.x, 5.x) |
| Vite | ✅ | 推荐使用 |
| Rollup | ✅ | 完整支持 |
| Parcel | ✅ | 完整支持 |
| esbuild | ✅ | 完整支持 |
| Turbopack | ✅ | 实验性支持 |
### 模块系统
| 模块系统 | 支持状态 | 备注 |
| --------------- | ---- | ---------- |
| ES Module (ESM) | ✅ | 推荐使用 |
| CommonJS (CJS) | ✅ | 完整支持 |
| UMD | ✅ | 适用于浏览器直接引入 |
## 网络请求库兼容性
| 库/API | 自动追踪 | 手动追踪 | 备注 |
| -------------- | ---- | ---- | ---------------------- |
| Fetch API | ✅ | ✅ | 需要启用自动追踪配置 |
| XMLHttpRequest | ✅ | ✅ | 需要启用自动追踪配置 |
| Axios | ✅ | ✅ | 通过拦截器自动追踪 |
| jQuery.ajax | ⚠️ | ✅ | 基于 XMLHttpRequest,需要配置 |
## Web API 依赖
SDK 依赖以下 Web API,请确保目标浏览器支持:
### 必需的 API
| API | 用途 | 回退方案 |
| ---------------------- | --------- | ------------ |
| `navigator.sendBeacon` | 页面卸载时发送数据 | 使用 Fetch API |
| `fetch` | 数据上报 | 无 |
| `Promise` | 异步处理 | 无 |
| `JSON` | 数据序列化 | 无 |
### 可选的 API
| API | 用途 | 缺失时的影响 |
| ----------------------------- | --------- | ----------- |
| `PerformanceObserver` | 性能监控 | 部分性能指标不可用 |
| `PerformanceNavigationTiming` | 导航性能数据 | 无法获取导航性能指标 |
| `PerformanceResourceTiming` | 资源加载性能数据 | 无法获取资源性能指标 |
| `IntersectionObserver` | 元素可见性检测 | 部分用户行为追踪受影响 |
| `MutationObserver` | DOM 变化监控 | 部分自动追踪功能受影响 |
| `PerformanceLongTaskTiming` | 长任务检测 | 无法检测长任务 |
| `visibilitychange` 事件 | 页面可见性变化检测 | 部分会话追踪功能受影响 |
## TypeScript 支持
| TypeScript 版本 | 支持状态 | 备注 |
| ------------- | ---- | ----------- |
| 4.0+ | ✅ | 提供完整类型定义 |
| 3.8 - 3.9 | ⚠️ | 基本支持,部分类型受限 |
| \< 3.8 | ❌ | 不支持 |
SDK 提供完整的 TypeScript 类型定义文件(`.d.ts`),支持智能提示和类型检查。
## 内容安全策略(CSP)
如果您的网站使用了 CSP,需要在 CSP 策略中添加以下配置:
```http CSP 配置 theme={null}
Content-Security-Policy:
connect-src 'self' https://rum-intake.flashcat.cloud;
script-src 'self' 'unsafe-inline';
```
如果使用 CDN 方式接入,还需要在 `script-src` 中添加 `https://static.flashcat.cloud`。
## 隐私和安全
### Cookie 使用
SDK 可能使用以下类型的存储:
| 存储类型 | 用途 | 是否必需 |
| -------------- | --------- | ---- |
| localStorage | 会话状态持久化 | 可选 |
| sessionStorage | 临时会话数据 | 可选 |
| Cookie | 用户标识(可配置) | 可选 |
可以通过配置禁用 Cookie 和本地存储,使用纯内存模式。
### SameSite Cookie
SDK 默认使用 `SameSite=Lax` 策略,兼容现代浏览器的隐私要求。
## 已知限制
| 限制项 | 说明 |
| -------------- | --------------------------- |
| **长任务检测** | Safari 不支持 Long Tasks API |
| **Web Vitals** | 仅支持 FID,不支持 CLS 和 LCP 的完整测量 |
| **资源大小信息** | 部分资源大小信息可能不准确 |
| **页面隐藏时数据发送** | iOS Safari 页面隐藏时无法保证数据立即发送 |
| 限制项 | 说明 |
| -------------- | ---------------------------- |
| **长任务检测** | Firefox 不支持 Long Tasks API |
| **浏览器干预检测** | Firefox 不支持 Intervention API |
| **Web Vitals** | 仅支持 FID |
* **后台运行限制** - 移动浏览器在后台时可能暂停 JavaScript 执行
* **内存限制** - 移动设备内存受限,可能影响数据缓存能力
* **网络限制** - 移动网络不稳定可能导致数据上报延迟
* 需要启用路由变化追踪配置
* 某些框架的路由库需要额外配置
* 建议手动调用 `startView` 方法追踪路由变化
请参阅 [高级配置](/zh/rum/sdk/web/advanced-config#覆盖默认-rum-视图名称) 了解 SPA 路由追踪的详细配置。
## 性能影响
FlashCat Web SDK 设计为轻量级,对网页性能的影响极小:
* **SDK 大小**:约 30 KB(gzip 后约 10 KB)
* **运行时内存占用**:\< 2 MB
* **CPU 占用**:\< 1%
* **首次加载影响**:\< 50ms
## 更新策略
* **主版本更新**:可能包含不兼容的更改,需要代码调整
* **次版本更新**:新增功能,向后兼容
* **补丁版本更新**:bug 修复,完全向后兼容
建议定期更新 SDK 到最新稳定版本以获得最佳性能和安全性。
## 最低部署要求
为了确保 SDK 正常工作,请确保:
1. **浏览器版本**:
* Chrome 63+
* Firefox 67+
* Safari 12.1+
* Edge 79+
2. **JavaScript 支持**:ES6+ (ES2015)
3. **必需的 Web API**:
* `fetch` API
* `Promise`
* `JSON`
4. **网络访问**:应用需要能够访问 `https://rum-intake.flashcat.cloud` 以上报数据
5. **HTTPS**:推荐在 HTTPS 环境下使用以获得完整功能支持
## 相关文档
了解如何集成 SDK
了解 SDK 的高级配置选项
了解 SDK 收集哪些数据
# Web SDK 数据收集
Source: https://docs.flashduty.com/zh/rum/sdk/web/data-collection
详细了解 Web RUM SDK 收集的数据类型、事件属性、性能指标以及数据存储机制
Web RUM SDK 自动收集丰富的用户行为和性能数据。每个 RUM 事件都包含默认属性(如 `view.url`、`device.type`、`geo.country`)以及特定事件类型的附加指标和属性。
## 默认属性
Web RUM SDK 会自动捕获以下默认属性,这些属性适用于所有 RUM 事件类型。
| 属性 | 类型 | 描述 |
| ---------------- | --- | ----------------------------------------------------- |
| `date` | 整数 | 事件的时间戳(以毫秒为单位,epoch 毫秒) |
| `type` | 字符串 | 事件的类型(如 `session`、`view`、`resource`、`error`、`action`) |
| `application.id` | 字符串 | 应用的唯一标识符 |
| `service` | 字符串 | 生成此事件的服务名称 |
| `env` | 字符串 | 应用的环境名称(如 `prod`、`dev`、`staging`) |
| `version` | 字符串 | 应用版本 |
| `sdk_version` | 字符串 | RUM SDK 版本 |
| 属性 | 类型 | 描述 |
| -------------- | --- | ------------------------------------------------ |
| `device.type` | 字符串 | 设备类型(如 `Desktop`、`Mobile`、`Tablet`、`TV`、`Other`) |
| `device.brand` | 字符串 | 设备品牌(如 `Apple`、`Samsung`、`Huawei`) |
| `device.model` | 字符串 | 设备型号(如 `iPhone`、`iPad`) |
| `device.name` | 字符串 | 设备的商业名称 |
| 属性 | 类型 | 描述 |
| ------------------ | --- | ---------------------------------- |
| `os.name` | 字符串 | 操作系统名称(如 `Mac OS`、`Windows`、`iOS`) |
| `os.version` | 字符串 | 操作系统版本号(如 `10.15.7`、`11.0`) |
| `os.version_major` | 字符串 | 操作系统主版本号(如 `10`、`11`) |
| 属性 | 类型 | 描述 |
| ------------------------- | --- | ------------------------------------------- |
| `browser.name` | 字符串 | 浏览器名称(如 `Chrome`、`Firefox`、`Safari`、`Edge`) |
| `browser.version` | 字符串 | 浏览器版本号(如 `91.0.4472.124`) |
| `browser.version_major` | 字符串 | 浏览器主版本号(如 `91`) |
| `browser.user_agent` | 字符串 | User Agent 字符串 |
| `browser.viewport.width` | 数字 | 浏览器视口宽度(像素) |
| `browser.viewport.height` | 数字 | 浏览器视口高度(像素) |
| 属性 | 类型 | 描述 |
| ------------------------- | --- | --------------------------- |
| `geo.country` | 字符串 | 国家名称 |
| `geo.country_iso_code` | 字符串 | 国家的 ISO 代码(如 `US`、`CN`) |
| `geo.country_subdivision` | 字符串 | 国家的一级行政区划(如美国的州、中国的省) |
| `geo.continent_code` | 字符串 | 洲的 ISO 代码(如 `EU`、`AS`、`NA`) |
| `geo.continent` | 字符串 | 洲名称 |
| `geo.city` | 字符串 | 城市名称 |
地理位置信息由 FlashCat 后端根据客户端 IP 地址推断,不会在客户端收集精确的 GPS 位置。
| 属性 | 类型 | 描述 |
| ----------- | --- | ------------------------ |
| `usr.id` | 字符串 | 用户的唯一标识符 |
| `usr.name` | 字符串 | 用户友好名称,默认显示在 RUM UI 中 |
| `usr.email` | 字符串 | 用户电子邮件地址。如果没有用户名,则显示电子邮件 |
您还可以添加自定义用户属性,例如 `usr.plan`、`usr.role` 等。要设置用户信息,请参阅 [SDK 接入指南](/zh/rum/sdk/web/sdk-integration#自定义用户标识)。
## 事件特定属性
不同的事件类型具有特定的属性和指标。
| 属性 | 类型 | 描述 |
| --------------------------- | --- | -------------------------- |
| `session.id` | 字符串 | 会话的唯一标识符 |
| `session.type` | 字符串 | 会话类型(如 `user`、`synthetic`) |
| `session.is_active` | 布尔值 | 会话是否处于活动状态 |
| `session.initial_view.id` | 字符串 | 会话中初始视图的 ID |
| `session.initial_view.url` | 字符串 | 会话中初始视图的 URL |
| `session.initial_view.name` | 字符串 | 会话中初始视图的名称 |
| `session.last_view.id` | 字符串 | 会话中最后一个视图的 ID |
| `session.last_view.url` | 字符串 | 会话中最后一个视图的 URL |
| `session.last_view.name` | 字符串 | 会话中最后一个视图的名称 |
| `session.has_replay` | 布尔值 | 会话是否启用了会话重放 |
RUM 收集来自 [Navigation Timing API](https://www.w3.org/TR/navigation-timing/) 的所有性能指标,以及与 [Core Web Vitals](https://web.dev/vitals/) 相关的指标。
**Core Web Vitals**
| 属性 | 类型 | 描述 |
| -------------------------------- | ------ | ------------------------------------- |
| `view.largest_contentful_paint` | 数字(纳秒) | 最大内容绘制时间(LCP),视口中最大可见内容元素的渲染时间 |
| `view.first_input_delay` | 数字(纳秒) | 首次输入延迟(FID),用户首次与页面交互到浏览器实际响应该交互之间的时间 |
| `view.cumulative_layout_shift` | 数字 | 累积布局偏移(CLS),量化了视口内可见元素的意外移动 |
| `view.interaction_to_next_paint` | 数字(纳秒) | 交互到下次绘制(INP),测量用户与页面进行所有交互的延迟 |
**导航性能指标**
| 属性 | 类型 | 描述 |
| ----------------------------- | ------ | ------------------------------------------------- |
| `view.time_spent` | 数字(纳秒) | 用户在该视图上花费的时间 |
| `view.loading_time` | 数字(纳秒) | 页面完全加载所需的时间(`loadEventEnd` 时触发) |
| `view.first_contentful_paint` | 数字(纳秒) | 首次内容绘制时间(FCP),浏览器首次渲染任何文本、图像、非空白 canvas 或 SVG 的时间 |
| `view.first_byte` | 数字(纳秒) | 首字节时间(TTFB),从用户发起页面加载到浏览器接收 HTML 文档第一个字节的时间 |
| `view.dom_interactive` | 数字(纳秒) | 解析器完成对主文档的工作的时刻(`domInteractive`) |
| `view.dom_content_loaded` | 数字(纳秒) | 初始 HTML 文档完全加载和解析的时间 |
| `view.dom_complete` | 数字(纳秒) | 页面和所有子资源准备就绪的时间(`domComplete`) |
| `view.load_event` | 数字(纳秒) | 触发 load 事件的时间(`loadEventEnd`),表示页面完全加载 |
**网络耗时指标**
| 属性 | 类型 | 描述 |
| ------------------------------------- | ------ | ---------------- |
| `view.redirect.duration` | 数字(纳秒) | 重定向所花费的时间 |
| `view.dns.duration` | 数字(纳秒) | DNS 查询所花费的时间 |
| `view.connect.duration` | 数字(纳秒) | 建立服务器连接所花费的时间 |
| `view.ssl.duration` | 数字(纳秒) | TLS 握手所花费的时间 |
| `view.request.duration` | 数字(纳秒) | 请求 HTML 文档所花费的时间 |
| `view.response.duration` | 数字(纳秒) | 下载 HTML 文档所花费的时间 |
| `view.in_foreground_periods.count` | 数字 | 视图处于前台的次数 |
| `view.in_foreground_periods.duration` | 数字(纳秒) | 视图处于前台的总时间 |
| 属性 | 类型 | 描述 |
| ---------------------- | --- | -------------------- |
| `view.id` | 字符串 | 视图的唯一标识符 |
| `view.url` | 字符串 | 视图的 URL |
| `view.name` | 字符串 | 视图的可自定义名称 |
| `view.referrer` | 字符串 | 前一个页面的 URL(referrer) |
| `view.action.count` | 数字 | 该视图中收集的用户操作数 |
| `view.error.count` | 数字 | 该视图中收集的错误数 |
| `view.resource.count` | 数字 | 该视图中收集的资源数 |
| `view.long_task.count` | 数字 | 该视图中收集的长任务数 |
| `view.is_active` | 布尔值 | 视图是否处于活动状态 |
RUM 会收集来自 [Resource Timing API](https://www.w3.org/TR/resource-timing-2/) 的详细网络时间信息,用于单个资源的加载。
| 属性 | 类型 | 描述 |
| --------------------------------- | ------ | ------------------------------------ |
| `resource.duration` | 数字(纳秒) | 加载资源所需的总时间 |
| `resource.size` | 数字(字节) | 资源大小 |
| `resource.connect.duration` | 数字(纳秒) | 建立服务器连接所需的时间 |
| `resource.ssl.duration` | 数字(纳秒) | TLS 握手所需的时间(仅 HTTPS) |
| `resource.dns.duration` | 数字(纳秒) | DNS 解析所需的时间 |
| `resource.redirect.duration` | 数字(纳秒) | 重定向所需的时间 |
| `resource.first_byte.duration` | 数字(纳秒) | 等待接收响应首字节的时间 |
| `resource.download.duration` | 数字(纳秒) | 下载响应的时间 |
| `resource.render_blocking_status` | 字符串 | 资源的渲染阻塞状态(`blocking`、`non-blocking`) |
| `resource.first_party` | 布尔值 | 是否为第一方资源(与应用同域) |
| 属性 | 类型 | 描述 |
| -------------------------- | --- | -------------------------------------------------------- |
| `resource.id` | 字符串 | 资源的唯一标识符 |
| `resource.type` | 字符串 | 资源类型(如 `xhr`、`fetch`、`css`、`js`、`image`、`font`、`media`) |
| `resource.method` | 字符串 | HTTP 方法(如 `GET`、`POST`、`PUT`、`DELETE`) |
| `resource.status_code` | 数字 | HTTP 响应状态码 |
| `resource.url` | 字符串 | 资源 URL |
| `resource.url_host` | 字符串 | URL 的主机部分 |
| `resource.url_path` | 字符串 | URL 的路径部分 |
| `resource.url_query` | 对象 | URL 的查询参数,以键值对形式解析 |
| `resource.url_scheme` | 字符串 | URL 的协议(如 `https`、`http`) |
| `resource.provider.name` | 字符串 | 资源提供者名称,默认为 `unknown` |
| `resource.provider.domain` | 字符串 | 资源提供者域名 |
| `resource.provider.type` | 字符串 | 资源提供者类型(如 `first-party`、`cdn`、`ad`、`analytics`、`social`) |
如果启用了 GraphQL 请求追踪,以下属性会附加到 `resource` 事件上:
| 属性 | 类型 | 描述 |
| --------------------------------- | --- | ------------------------------------------------- |
| `resource.graphql.operation_type` | 字符串 | GraphQL 操作类型(`query`、`mutation`、`subscription`) |
| `resource.graphql.operation_name` | 字符串 | GraphQL 操作名称(如果在请求中提供) |
| `resource.graphql.variables` | 字符串 | 随请求发送的 GraphQL 变量 |
| `resource.graphql.payload` | 字符串 | GraphQL 查询(限制为 32 KB,仅在启用 `trackPayload` 时可用) |
| `resource.graphql.errors_count` | 数字 | GraphQL 响应中返回的错误数(仅在启用 `trackResponseErrors` 时可用) |
| `resource.graphql.errors` | 数组 | GraphQL 错误数组,包含 message、code、locations 和 path |
长任务是指阻塞主线程 50 毫秒或更长时间的任务。这些任务会导致高输入延迟、慢速交互或卡顿的动画/滚动。
| 属性 | 类型 | 描述 |
| --------------------------- | ------ | -------------------- |
| `long_task.duration` | 数字(纳秒) | 长任务的持续时间 |
| `long_task.is_frozen_frame` | 布尔值 | 是否为冻结帧(持续时间超过 700ms) |
长任务检测仅在支持 Long Tasks API 的浏览器中可用(Chrome、Edge)。Safari 和 Firefox 不支持此功能。
前端错误通过 RUM 收集。错误消息和堆栈跟踪(如果可用)会包含在内。
**通用错误属性**
| 属性 | 类型 | 描述 |
| ---------------------- | --- | --------------------------------------------------------------------------------- |
| `error.id` | 字符串 | 错误的唯一标识符 |
| `error.source` | 字符串 | 错误来源(如 `console`、`network`、`source`、`logger`、`agent`、`webview`、`custom`、`report`) |
| `error.type` | 字符串 | 错误类型(在某些情况下为错误代码) |
| `error.message` | 字符串 | 简洁、易读的单行错误消息 |
| `error.stack` | 字符串 | 错误的堆栈跟踪或补充信息 |
| `error.issue_id` | 字符串 | 错误问题的唯一标识符(相同错误会被聚合到同一 issue) |
| `error.fingerprint` | 字符串 | 用于唯一标识错误的指纹 |
| `error.handling` | 字符串 | 错误处理方式(`handled`、`unhandled`) |
| `error.handling_stack` | 字符串 | 错误处理时的堆栈跟踪 |
| `error.causes` | 数组 | 导致此错误的其他错误信息 |
**网络错误属性**
网络错误包含有关失败 HTTP 请求的信息:
| 属性 | 类型 | 描述 |
| -------------------------------- | --- | ----------------------------------------------- |
| `error.resource.status_code` | 数字 | HTTP 响应状态码 |
| `error.resource.method` | 字符串 | HTTP 方法(如 `GET`、`POST`) |
| `error.resource.url` | 字符串 | 资源 URL |
| `error.resource.url_host` | 字符串 | URL 的主机部分 |
| `error.resource.url_path` | 字符串 | URL 的路径部分 |
| `error.resource.url_scheme` | 字符串 | URL 的协议 |
| `error.resource.provider.name` | 字符串 | 资源提供者名称,默认为 `unknown` |
| `error.resource.provider.domain` | 字符串 | 资源提供者域名 |
| `error.resource.provider.type` | 字符串 | 资源提供者类型(如 `first-party`、`cdn`、`ad`、`analytics`) |
有关不同 JavaScript 错误类型的更多信息,请参阅 [MDN 文档](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)。
**操作时间属性**
| 属性 | 类型 | 描述 |
| ------------------------ | ------ | ---------- |
| `action.loading_time` | 数字(纳秒) | 操作的加载时间 |
| `action.long_task.count` | 数字 | 该操作触发的长任务数 |
| `action.resource.count` | 数字 | 该操作触发的资源数 |
| `action.error.count` | 数字 | 该操作触发的错误数 |
**操作标识属性**
| 属性 | 类型 | 描述 |
| -------------------- | --- | ---------------------------------------------------------- |
| `action.id` | 字符串 | 用户操作的唯一标识符(UUID) |
| `action.type` | 字符串 | 用户操作类型(如 `click`、`custom`)。对于自定义用户操作,设置为 `custom` |
| `action.target.name` | 字符串 | 用户交互的元素。仅适用于自动收集的操作 |
| `action.name` | 字符串 | 用户友好的名称(如 `Click on #checkout`)。对于自定义用户操作,为 API 调用中给定的操作名称 |
RUM 会自动检测用户的挫败信号,帮助您了解用户在应用中遇到的问题。
| 属性 | 类型 | 描述 |
| ------------------------------------- | --- | ------------------------- |
| `session.frustration.count` | 数字 | 会话中所有挫败信号的数量 |
| `view.frustration.count` | 数字 | 视图中所有挫败信号的数量 |
| `action.frustration.type:dead_click` | 字符串 | RUM SDK 检测到的死点击(点击无响应) |
| `action.frustration.type:rage_click` | 字符串 | RUM SDK 检测到的暴怒点击(连续快速点击) |
| `action.frustration.type:error_click` | 字符串 | RUM SDK 检测到的错误点击(点击后触发错误) |
挫败信号是识别用户体验问题的重要指标。死点击和暴怒点击通常表明 UI 响应不及时或交互设计存在问题。
如果 URL 中包含 UTM 参数,RUM 会自动捕获以下属性,用于追踪营销活动:
| 属性 | 类型 | 描述 |
| ----------------------------- | --- | ------------------------- |
| `view.url_query.utm_source` | 字符串 | URL 中追踪流量来源的参数 |
| `view.url_query.utm_medium` | 字符串 | URL 中追踪流量来自哪个渠道的参数 |
| `view.url_query.utm_campaign` | 字符串 | URL 中标识与该视图关联的特定营销活动的参数 |
| `view.url_query.utm_content` | 字符串 | URL 中标识用户在营销活动中点击的特定元素的参数 |
| `view.url_query.utm_term` | 字符串 | URL 中追踪用户搜索以触发给定活动的关键字的参数 |
## 数据存储
在上传到 FlashCat 之前,数据会以明文形式临时存储在浏览器的本地存储(LocalStorage 或 SessionStorage)中。
SDK 将事件添加到内存中的批次缓冲区。
当网络不可用时,批次会被保留在本地存储中。
网络可用时,数据以批次形式发送到服务器。
超过一定时限的数据会被自动清理,以避免占用过多存储空间。
敏感数据不应包含在 RUM 事件中,或者应在发送前通过 `beforeSend` 回调进行混淆或过滤。
## 数据上传
Web RUM SDK 会将收集到的事件以批次形式上传到服务器,以优化网络性能和减少对用户体验的影响。
### 批次上传触发条件
* 批次中的事件数量达到阈值
* 批次大小达到阈值
* 定期上传(例如每 10 秒)
* 页面卸载时(`beforeunload` 事件)
### 上传策略
| 策略 | 说明 |
| ---------------------- | ----------------------------------------------- |
| **Beacon API** | 优先使用,确保在页面卸载时数据不会丢失 |
| **XHR/Fetch Fallback** | 如果 Beacon API 不可用,使用 XMLHttpRequest 或 Fetch API |
| **失败重试** | 如果上传失败,批次会被保留在本地存储,直到成功发送 |
| **数据压缩** | 上传前对批次数据进行压缩,减少网络流量 |
## 隐私和合规
可配置 SDK 对 IP 地址进行匿名化处理
使用 `beforeSend` 回调过滤或混淆敏感信息
可配置是否使用 Cookie 和本地存储
支持用户隐私选择退出机制
有关隐私配置的详细信息,请参阅 [高级配置](/zh/rum/sdk/web/advanced-config#用户跟踪同意)。
## 更多信息
了解如何在 Web 应用中接入 RUM SDK
了解如何配置 SDK 的高级功能
了解 SDK 的浏览器和框架兼容性
# Web SDK 问题排查
Source: https://docs.flashduty.com/zh/rum/sdk/web/faq
解决 Web RUM SDK 使用过程中的常见问题,包括数据采集异常、SDK 配置和性能优化
本指南帮助您解决 Web RUM SDK 使用过程中可能遇到的常见问题,包括数据采集异常、SDK 配置问题和性能优化等方面。
## 数据采集验证
如果您在 RUM 平台上看不到数据,请按以下步骤进行检查。
### SDK 安装检查
确认 RUM SDK 是否正确引入:
```html CDN 引入 theme={null}
```
```javascript npm 引入 theme={null}
import { flashcatRum } from "@flashcatcloud/browser-rum";
flashcatRum.init({
applicationId: "您的应用ID",
clientToken: "您的客户端令牌",
service: "",
env: "",
version: "1.0.0"
});
```
打开浏览器开发者工具(F12),查看 Console 面板是否有 JavaScript 报错。
确认应用 ID 和客户端令牌是否与 RUM 控制台中的配置一致。
### 网络请求检查
1. 打开浏览器开发者工具的 **Network** 面板
2. 筛选 `browser.flashcat.cloud` 的请求
3. 确认请求状态码为 `200`
4. 如果请求失败,查看具体错误信息
如果看到 CORS 错误,请检查您的 CSP 配置是否正确。
### 浏览器兼容性
确认您使用的浏览器版本是否受支持:
| 浏览器 | 最低版本 |
| ----------------- | ---------- |
| Chrome | 60+ |
| Firefox | 60+ |
| Safari | 12+ |
| Edge | 15+ |
| Internet Explorer | 11(部分功能受限) |
### 广告拦截器影响
部分广告拦截插件可能会阻止 RUM SDK 的运行。建议将您的域名和 `browser.flashcat.cloud` 加入白名单。
## 常见问题解决
**问题**:已完成 SDK 配置,但平台上没有数据。
**解决方案**:
1. **等待数据同步**:数据一般在 2-5 分钟内显示
2. **检查初始化时机**:确保 SDK 在页面加载时就完成初始化
3. **检查采样率**:确认采样率设置合理
```javascript theme={null}
flashcatRum.init({
// ... 其他配置
sessionSampleRate: 100 // 设为 100 表示采集所有会话
});
```
4. **检查用户授权**:确认用户跟踪授权状态
```javascript theme={null}
flashcatRum.setTrackingConsent("granted");
```
**问题**:用户行为数据不完整。
**解决方案**:
1. **启用行为跟踪**:
```javascript theme={null}
flashcatRum.init({
// ... 其他配置
trackUserInteractions: true
});
```
2. **为自定义元素添加标记**:
```html theme={null}
提交
```
3. **手动记录复杂交互**:
```javascript theme={null}
flashcatRum.addAction("click", "自定义按钮点击");
```
**问题**:JavaScript 异常未被记录。
**解决方案**:
1. **启用异常跟踪**:
```javascript theme={null}
flashcatRum.init({
// ... 其他配置
trackErrors: true
});
```
2. **手动上报 try-catch 中的异常**:
```javascript theme={null}
try {
// 可能出错的代码
} catch (error) {
console.error(error);
flashcatRum.addError(error);
}
```
3. **配置 Source Map**:便于定位生产环境的问题,详见 [Source Mapping](/zh/rum/error-tracking/source-mapping)
**问题**:担心 RUM SDK 影响网站性能。
**解决方案**:
1. **只启用必要的功能**:
```javascript theme={null}
flashcatRum.init({
// ... 其他配置
trackResources: true,
trackLongTasks: false, // 关闭不需要的功能
trackErrors: true,
trackUserInteractions: true
});
```
2. **调整采样率**:
```javascript theme={null}
flashcatRum.init({
// ... 其他配置
sessionSampleRate: 50 // 只采集 50% 的会话
});
```
3. **过滤非关键资源**:
```javascript theme={null}
flashcatRum.init({
// ... 其他配置
beforeSend: (event) => {
// 过滤掉非关键资源
if (event.type === 'resource' && event.resource.url.includes('/static/')) {
return false;
}
return true;
}
});
```
**问题**:CSP 策略阻止 RUM SDK 运行。
**解决方案**:
在您的 CSP 配置中添加以下规则:
```
script-src 'self' https://static.flashcat.cloud;
connect-src 'self' https://browser.flashcat.cloud;
```
**问题**:SPA 应用的路由切换未被记录。
**解决方案**:
```javascript theme={null}
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
function RumRouteTracker() {
const location = useLocation();
useEffect(() => {
flashcatRum.startView({
name: location.pathname,
url: location.pathname + location.search
});
}, [location]);
return null;
}
// 在 App 组件中使用
function App() {
return (
{/* 其他路由 */}
);
}
```
```javascript theme={null}
router.afterEach((to) => {
flashcatRum.startView({
name: to.name || to.path,
url: to.fullPath
});
});
```
```javascript theme={null}
// 路由变化时调用
flashcatRum.startView({
name: "商品详情页",
url: "/products/123"
});
```
## 高级调试
### 启用调试模式
开启调试模式可在控制台获取详细日志:
```javascript theme={null}
flashcatRum.init({
// ... 其他配置
debug: true
});
```
### 强制数据采集
测试时可强制开启全量数据采集:
```javascript theme={null}
flashcatRum.init({
// ... 其他配置
sessionSampleRate: 100,
sessionReplaySampleRate: 100
});
```
请勿在生产环境使用 100% 采样率,以避免产生过多数据和费用。
### 控制台调试命令
在浏览器控制台中可使用以下命令:
```javascript theme={null}
// 获取 RUM 内部上下文
window.FC_RUM.getInternalContext();
// 获取当前会话 ID
window.FC_RUM.getSessionId();
// 获取当前页面 ID
window.FC_RUM.getViewId();
// 手动发送测试事件
window.FC_RUM.addAction('test', 'debug_action');
```
### 网络请求分析
1. 打开开发者工具 **Network** 面板
2. 筛选 `browser.flashcat.cloud` 请求
3. 查看请求 Payload 确认数据内容
4. 检查 Response 确认上报成功
## 常见问题解答
一般在 2-5 分钟内显示,高峰期可能稍有延迟。
支持 iOS Safari 和 Android Chrome 等主流移动端浏览器,但部分高级功能(如 Long Tasks 监控)可能受限。
可以根据 URL 条件判断是否初始化:
```javascript theme={null}
// 排除管理后台页面
if (!window.location.pathname.startsWith("/admin")) {
flashcatRum.init({
// ... 配置
});
}
```
需要以下配置:
1. 使用相同的应用 ID 和客户端令牌
2. 设置一致的用户标识
3. 启用跨域跟踪:
```javascript theme={null}
flashcatRum.init({
// ... 其他配置
allowedTracingUrls: [
"https://example.com",
"https://app.example.com",
"https://shop.example.com"
]
});
```
可以通过以下方式:
1. **降低采样率**:设置 `sessionSampleRate` 为 10-50
2. **关闭不必要的功能**:如 `trackLongTasks: false`
3. **排除特定页面**:不在管理后台等内部页面初始化
4. **配置数据过滤**:使用 `beforeSend` 过滤非关键数据
## 联系技术支持
如果按上述步骤排查后仍有问题,请联系我们的技术支持团队。
请收集以下信息:
* 应用 ID
* 浏览器类型和版本
* SDK 版本
* 控制台错误截图
* Network 面板请求截图
* 问题复现步骤
* **邮箱**:[support@flashcat.cloud](mailto:support@flashcat.cloud)
* **在线咨询**:点击平台右下角「帮助」按钮
## 相关文档
了解如何快速接入 RUM SDK
了解 SDK 的高级配置功能
了解浏览器和框架兼容性
# Web SDK 性能影响
Source: https://docs.flashduty.com/zh/rum/sdk/web/performance-impact
了解 Flashduty Web RUM SDK 接入后对页面加载、运行时 CPU、内存与网络上报的影响,以及性能优化建议。
## 概述
在 Web 应用中接入 RUM SDK 时,了解其性能影响对于维护良好的用户体验至关重要。Flashduty Web RUM SDK 在设计时以最小化页面开销为目标,并提供透明、可复现的基准数据,帮助您评估 SDK 是否符合页面的性能预算。
接入 SDK 主要会引入三类开销:
1. **加载开销**:SDK JS 的下载、解析与初始化,影响首屏与可交互时间。
2. **运行时开销**:事件采集、自动埋点(资源、长任务、用户交互)与 Session Replay 录制占用的主线程 CPU 与内存。
3. **网络开销**:周期性批量上报产生的请求数量与体积。
整体而言,**基础 RUM 的开销很小**,对绝大多数页面可忽略;**Session Replay(会话录制)是开销的主要来源**,尤其在 DOM 规模大、变更频繁的页面上更为明显,应通过采样率与隐私配置加以控制。
## 综合性能影响一览
下表为**典型业务页面**(含点击、输入、XHR)在**推荐生产配置**(RUM + 资源 + 长任务采集,Session Replay 按需采样)下相对无 SDK 基线的整体影响(p50):
| 指标 | 无 SDK(基线) | 接入 SDK(推荐配置) | 影响 | 评估 |
| ------------ | --------- | ------------ | ------------------- | -- |
| SDK 体积(gzip) | — | 50.0 KB | +50.0 KB(异步/CDN 缓存) | 极小 |
| SDK 初始化耗时 | — | 7.8 ms | +7.8 ms | 极小 |
| 首屏 FCP | 20 ms | 44 ms | +24 ms | 极小 |
| 主线程 CPU(运行期) | 42 ms | 78 ms | +36 ms | 较小 |
| JS Heap 峰值 | 1.24 MB | 3.07 MB | +1.83 MB | 较小 |
| 上报体积(每会话窗口) | 0 KB | 30.5 KB | +30.5 KB | 较小 |
评估口径:极小(可忽略)\< 较小 \< 中等 \< 较大。CPU/内存为整个 10s 交互窗口的累计值,折算到每秒均极低;SDK 体积通过 CDN 异步加载,不阻塞首屏关键渲染路径。以上为典型场景参考值,实际影响会因页面复杂度、设备性能与 SDK 配置不同而有所差异。
## SDK 资源体积
| Bundle | 说明 | 原始 | Gzip | Brotli |
| ----------------- | ------------------------ | -------- | ------- | ------- |
| `flashcat-rum.js` | 完整 RUM(含 Session Replay) | 145.3 KB | 50.0 KB | 43.6 KB |
实际传输以 **Gzip / Brotli 压缩后体积** 为准。SDK 通过 CDN 异步加载时不阻塞首屏关键路径;Session Replay 的录制器(recorder)为按需懒加载,仅在开启录制时才下载。
## Session Replay 额外开销
会话录制是独立可选能力,开销与页面特征强相关。下表为开启 Session Replay 100% 录制后,相对推荐配置的**额外**增量(p50):
| 场景 | CPU 增量 (ms) | JS Heap 增量 (MB) | 录制上报体积 (KB) | 评估 |
| ----------- | ----------- | --------------- | ----------- | -- |
| 典型业务页 | +11 | +0.3 | 35 | 极小 |
| SPA 路由页 | +45 | +1.5 | 125 | 较小 |
| 高频 DOM 更新页 | +73 | +0.7 | 10 | 极小 |
| 大表格页(大 DOM) | +757 | +39.5 | 1757 | 较大 |
Session Replay 在普通页面上开销可控,但在**大 DOM / 高频变更**页面上会显著放大——DOM 越大首次快照序列化越重,变更越频繁增量录制与上报体积越大。强烈建议通过 `sessionReplaySampleRate` 降低录制比例,并配合隐私脱敏与区域排除控制开销。
## 性能影响详解
在页面早期同步执行一次,完成配置解析、上下文采集与各 feature 注册,耗时通常毫秒级,对 FCP/LCP 影响极小。
通过 PerformanceObserver 监听 resource timing,开销随页面请求数量增长,但属被动监听,CPU 占用低。
监听 `longtask` entry,仅记录已发生的长任务,本身几乎不引入额外长任务。
监听点击等事件并推断元素名称,单次交互开销极小。
* 初始全量快照需序列化整棵 DOM 树,**DOM 越大,首次录制开销越高**(见大表格页)。
* 通过 MutationObserver 持续记录增量变更,**DOM 变更越频繁,CPU 与上报体积越高**(见高频 DOM 更新页)。
* 录制数据经 Web Worker 压缩后上报,压缩在 Worker 线程进行避免阻塞主线程,但仍带来内存与网络增量。
## 性能优化建议
不需要会话录制时使用 `flashcat-rum-slim`,体积更小(gzip 36.2 KB vs 50.0 KB)。
`sessionSampleRate` 控制纳入 RUM 的会话比例;`sessionReplaySampleRate` **单独控制录制比例**(建议远低于 100%):
```javascript theme={null}
flashcatRum.init({
applicationId: "",
clientToken: "",
site: "rum-server.flashcat.cloud",
sessionSampleRate: 100, // 采集 RUM 的会话比例
sessionReplaySampleRate: 10, // 仅 10% 会话录制,显著降低录制开销
trackResources: true,
trackLongTasks: true,
trackUserInteractions: true,
defaultPrivacyLevel: "mask-user-input",
});
flashcatRum.startSessionReplayRecording();
```
用 `defaultPrivacyLevel`(`mask` / `mask-user-input` / `allow`)脱敏;对超大/高频变更区域使用隐私标记排除,减少序列化与上报体积。
`beforeSend` 对**每个** RUM 事件回调,避免在其中编写重逻辑或同步阻塞操作。
不关注资源或长任务时,可分别关闭 `trackResources` / `trackLongTasks`。
通过 CDN `async` 加载,避免阻塞首屏关键渲染路径。
## 离线缓存与上报
SDK 将事件先写入本地缓冲,由后台批处理按节奏批量上报(带退避重试),并在页面卸载(`visibilitychange` / `beforeunload`)时通过 `sendBeacon` 兜底发送,降低数据丢失。上报失败按重试策略退避,不会无限占用网络。
## 测试方法
* **设备/环境**:Apple M4(10 核 / 16 GB),Darwin 24.5.0 arm64,Chromium 147。
* **工具**:Playwright 驱动 Chromium,配合 CDP `Performance.getMetrics` 采集 CPU / 内存 / DOM 节点;`PerformanceObserver` 采集 FCP / LCP / CLS / INP / Long Task。
* **对照组**:A 无 SDK(基线)、B 基础 RUM、C RUM + 资源 + 长任务(推荐生产配置)、D + Session Replay 100%。读数对比时:`B − A` = 基础 RUM 开销,`C − B` = 自动埋点增量,`D − C` = Session Replay 额外开销。
* **口径**:取 **p50**,而非平均值;JS Heap 在强制 GC 后读取"回收后"值;上报请求数与体积从真实网络统计,与传输方式(fetch / beacon)无关;无 SDK 组不加载任何 SDK 字节。
影响随**页面复杂度、设备性能、SDK 配置**变化,建议在自身关键页面上用基准工具实测。
## 相关文档
了解如何接入 Web SDK
了解如何配置 SDK 的高级功能
了解 SDK 收集的数据类型
了解 SDK 支持的平台版本
# Web SDK 接入指南
Source: https://docs.flashduty.com/zh/rum/sdk/web/sdk-integration
快速了解如何在 Web 应用中集成 Web RUM SDK,包括 NPM、CDN 异步和 CDN 同步三种接入方式
RUM SDK 支持多种接入方式,您可以根据项目需求选择最适合的方案。
## 接入方式
我们提供三种接入方式:
| 接入方式 | 推荐场景 | 特点 |
| ---------- | --------- | ---------------- |
| **NPM** | 现代 Web 应用 | 与前端代码打包,对页面加载无影响 |
| **CDN 异步** | 有性能目标的应用 | 异步加载,不影响页面性能 |
| **CDN 同步** | 需要完整数据采集 | 同步加载,可捕获所有事件 |
NPM 和 CDN 异步方式可能会错过在 SDK 初始化之前触发的错误、资源和用户操作。如需完整采集,请使用 CDN 同步方式。
## 获取应用凭证
在 Flashduty 控制台的 [RUM 应用管理](https://console.flashcat.cloud/rum/apps)页面:
1. 创建或选择一个 Web 应用
2. 获取以下凭证信息:
* **Application ID** - 应用唯一标识符
* **Client Token** - 客户端访问令牌

## 接入代码
将 `@flashcatcloud/browser-rum` 添加到您的 `package.json` 文件中:
```bash theme={null}
npm install @flashcatcloud/browser-rum
```
然后在应用入口文件中初始化:
```javascript theme={null}
import { flashcatRum } from "@flashcatcloud/browser-rum";
flashcatRum.init({
applicationId: "",
clientToken: "",
service: "",
env: "",
version: "1.0.0",
sessionSampleRate: 100
});
```
将以下代码片段添加到每个需要监控的 HTML 页面的 `` 标签中:
```html theme={null}
```
将以下代码片段添加到 HTML 页面的 `` 标签最前面(在任何其他 `
```
您可以使用 `window.FC_RUM` 检查 SDK 是否加载成功,以便处理加载失败的情况。
## 初始化参数
### 必填参数
应用 ID,在应用管理页面获取
客户端 Token,在应用管理页面获取
服务名称,用于区分不同的服务
### 可选参数
环境标识,如 `production`、`staging` 等
应用版本号
要跟踪的会话百分比:100 为全部,0 为不采集
启用[会话重放](/zh/rum/session-replay/overview)功能的会话百分比
初始用户跟踪同意状态,详见[用户跟踪同意](/zh/rum/sdk/web/advanced-config#用户跟踪同意)
是否手动控制视图创建,详见[覆盖默认视图名称](/zh/rum/sdk/web/advanced-config#覆盖默认-rum-视图名称)
是否自动收集用户操作
是否启用资源事件收集
是否启用长任务事件收集
是否启用跨会话的匿名用户 ID 收集
会话重放隐私策略:`allow` 采集除密码外所有数据,`mask-user-input` 隐藏用户输入框内容,`mask` 隐藏所有文本
用于注入跟踪 Headers 的请求 URL 列表,详见[集成分布式追踪](/zh/rum/sdk/web/advanced-config#集成-rum-与分布式追踪)
要跟踪的请求百分比
可选代理 URL,例如:`https://www.proxy.com/path`
是否压缩发送到 Flashduty 的请求,在 Worker 线程中完成
是否将上下文存储在 localStorage 中以跨页面保留
## 应用场景
### 自定义用户标识
使用 `flashcatRum.setUser()` 为当前用户添加标识属性:
```javascript theme={null}
flashcatRum.setUser({
id: '1234',
name: 'John Doe',
email: 'john@doe.com',
plan: 'premium'
});
```
### 添加自定义 TAG
初始化 RUM 后,使用 `setGlobalContextProperty` API 为所有 RUM 事件添加额外的 TAG:
```javascript theme={null}
import { flashcatRum } from "@flashcatcloud/browser-rum";
flashcatRum.setGlobalContextProperty('activity', {
hasPaid: true,
amount: 23.42
});
```
### 发送自定义操作
使用 `addAction` API 创建 RUM 操作并附加上下文属性:
```javascript theme={null}
import { flashcatRum } from "@flashcatcloud/browser-rum";
function onCheckoutButtonClick(cart) {
flashcatRum.addAction("checkout", {
value: cart.value,
items: cart.items
});
}
```
### 自定义添加 Error
您可以通过 `dd_context` 属性为错误对象附加本地上下文:
```javascript theme={null}
const error = new Error("Something went wrong");
error.dd_context = { component: "Menu", param: 123 };
throw error;
```
## 验证接入
打开浏览器开发者工具,查看 Network 面板中是否有 `https://browser.flashcat.cloud/api/v2/rum` 的数据上报请求。
访问 Flashduty 控制台,查看 RUM 应用数据是否正常显示。
在页面上触发一些用户交互(点击、滚动等),验证数据采集是否正常。
数据通常在 2-5 分钟内显示在控制台中。
## 下一步
了解 SDK 的高级配置功能
了解 SDK 收集的数据类型
查看和分析 RUM 数据
# 高级配置
Source: https://docs.flashduty.com/zh/rum/sdk/wechat-miniprogram/advanced-config
配置微信小程序 RUM SDK 的代理、分布式追踪、会话、上下文和手动埋点
微信小程序 RUM SDK 的高级配置用于处理网络转发、链路追踪、会话控制、上下文补充和手动埋点。你可以在初始化时设置采集行为,也可以在运行时通过公开 API 补充事件。
## 上报地址和代理
SDK 默认将 RUM 数据发送到 `https://browser.flashcat.cloud/api/v2/rum`。如果小程序无法直接访问默认地址,或你需要先经过自己的网关,可以使用 `proxy`。
### 使用字符串代理
当 `proxy` 是字符串时,SDK 会去掉末尾多余的 `/`,并生成 `{proxy}?ddforward={encodedPath}`。其中 `ddforward` 是编码后的 `/api/v2/rum` 路径和查询参数。
```javascript app.js theme={null}
flashcatRum.init({
applicationId: "",
clientToken: "",
proxy: "https://rum-proxy.example.com/forward"
});
```
### 使用函数代理
当 `proxy` 是函数时,SDK 会把 `path` 和 `parameters` 交给你拼接完整 URL。`path` 固定为 `/api/v2/rum`,`parameters` 包含 `ddsource`、`ddtags`、`dd-api-key`、SDK 版本和批次时间等上报参数。
```javascript app.js theme={null}
flashcatRum.init({
applicationId: "",
clientToken: "",
proxy({ path, parameters }) {
return `https://rum-proxy.example.com${path}?${parameters}`;
}
});
```
未配置 `proxy` 时,SDK 使用 `site` 拼接上报地址:`https://{site}/api/v2/rum`。`site` 默认值为 `browser.flashcat.cloud`。
## 分布式追踪
SDK 可以为小程序网络请求注入 W3C Trace Context 格式的追踪头。启用后,命中采样的 `wx.request`、`wx.uploadFile` 和 `wx.downloadFile` 会携带 trace header,同时 resource 事件中会写入 `trace_id` 和 `span_id`。
```javascript app.js theme={null}
flashcatRum.init({
applicationId: "",
clientToken: "",
tracing: {
enabled: true,
sampleRate: 100,
headerName: "traceparent"
}
});
```
| 字段 | 类型 | 默认值 | 说明 |
| -------------------------- | ------- | ------------- | ----------------------------------------------- |
| `tracing.enabled` | boolean | `false` | 是否启用请求追踪头注入 |
| `tracing.sampleRate` | number | `100` | 请求追踪采样率,取值范围 0-100。`100` 表示全量采样,`50` 表示约 50% 采样 |
| `tracing.headerName` | string | `traceparent` | 注入到请求 header 中的字段名 |
| `tracing.rootTraceContext` | object | - | 可选根 Trace Context。配置后,SDK 会基于该上下文创建子 span |
SDK 生成的默认 header 值遵循 `00-{traceId}-{spanId}-{traceFlags}` 格式。例如:
```text theme={null}
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
```
如果配置了 `rootTraceContext`,SDK 会继承根上下文的 `traceId` 和 `traceFlags`,并生成新的 `spanId`;否则每个采样请求会创建新的 trace context。
## 会话行为
SDK 使用小程序存储保存当前会话,并把会话 ID 写入每个 RUM 事件。
| 行为 | 值 | 说明 |
| -------- | ----- | --------------------------------- |
| 会话过期时间 | 15 分钟 | 当前会话在最后一次扩展后 15 分钟过期 |
| 会话最长持续时间 | 4 小时 | 即使持续活跃,单个会话也不会超过 4 小时 |
| 会话扩展节流 | 1 分钟 | SDK 最多每分钟扩展一次会话过期时间 |
| 匿名用户 | 默认开启 | 未调用 `setUser()` 时,SDK 会为会话生成匿名 ID |
你可以在退出登录、切换账号或需要切分会话时调用 `stopSession()`。调用后,SDK 会清除当前会话;下一次事件会创建新的会话。
```javascript app.js theme={null}
flashcatRum.stopSession();
```
## 事件限流
SDK 会按事件类型进行每分钟限流,默认阈值为每种事件类型每分钟 `3000` 条。超过阈值后,SDK 会丢弃该类型后续事件,并生成一条来源为 `custom` 的错误事件说明限流情况。
```javascript app.js theme={null}
flashcatRum.init({
applicationId: "",
clientToken: "",
eventRateLimiterThreshold: 1000
});
```
如果你在短时间内主动上报大量自定义事件,请根据实际流量调整 `eventRateLimiterThreshold`,避免业务事件被限流。
## 发送前处理
`beforeSend` 会在 RUM 事件发送前执行。你可以在这里补充字段、脱敏上下文,或返回 `false` 丢弃当前事件。
```javascript app.js theme={null}
flashcatRum.init({
applicationId: "",
clientToken: "",
beforeSend(event) {
if (event.type === "resource" && event.resource?.url?.includes("/health")) {
return false;
}
event.context = {
...event.context,
source: "wechat-miniprogram"
};
}
});
```
## 用户和全局上下文
`setUser()` 设置当前用户信息。启用 `trackAnonymousUser` 且用户上下文为空时,SDK 会自动将匿名 ID 写入 `usr.id` 和 `usr.anonymous_id`;如果你设置了用户信息,SDK 会保留你的用户字段,并补充 `usr.anonymous_id`。
```javascript app.js theme={null}
flashcatRum.setUser({
id: "user-123",
name: "Alice",
role: "member"
});
```
`setGlobalContext()` 设置全局上下文。SDK 会把该对象写入后续事件的 `context` 字段。
```javascript app.js theme={null}
flashcatRum.setGlobalContext({
tenant: "acme",
region: "cn"
});
```
## 手动页面和自定义耗时
自动页面名称来自页面实例的 `route`。如果你需要记录虚拟页面,或希望用业务名称覆盖当前页面,可以调用 `startPage()`。
```javascript pages/product/detail.js theme={null}
flashcatRum.startPage("product_detail");
```
`addTiming()` 会把自定义耗时写入当前 view 的 `custom_timings`。如果传入 `time`,SDK 使用该时间点相对于当前页面开始时间的差值;未传入时使用当前时间。
```javascript pages/product/detail.js theme={null}
const start = Date.now();
loadProduct().then(() => {
flashcatRum.addTiming("product_loaded", Date.now());
});
```
自定义 timing 名称只保留字母、数字、`-`、`_`、`.`、`@` 和 `$`,其他字符会替换为 `_`。
## 手动操作、错误和自定义事件
```javascript pages/order/detail.js theme={null}
flashcatRum.addAction("submit_order", "tap");
flashcatRum.addError("payment failed", "custom");
flashcatRum.addCustomEvent("coupon_selected", {
couponId: "coupon-123",
discount: 20
});
```
| 方法 | 事件类型 | 说明 |
| ------------------------------------ | -------- | ------------------------------------ |
| `addAction(name, type?)` | `action` | 记录一次业务操作,`type` 默认是 `custom` |
| `addError(message, source?, stack?)` | `error` | 记录一次业务错误;公开 API 会把未传入的来源设置为 `custom` |
| `addCustomEvent(name, context?)` | `custom` | 记录自定义业务事件和上下文 |
## 相关页面
完成微信小程序 RUM SDK 安装和初始化。
了解小程序基础库版本、开发工具和平台 API 要求。
了解 SDK 自动采集的页面、操作、请求、错误和性能数据。
# 兼容性
Source: https://docs.flashduty.com/zh/rum/sdk/wechat-miniprogram/compatible
了解微信小程序 RUM SDK 的基础库版本、开发工具和平台 API 兼容性要求
微信小程序 RUM SDK 运行在微信小程序环境中,通过小程序基础库提供的生命周期、网络、存储、错误监听和性能 API 采集数据。接入前,请确认小程序的最低基础库版本和开发工具配置满足以下要求。
## 版本要求
| 项目 | 要求 | 说明 |
| ------- | -------------------------------- | --------------------------------------------------- |
| 小程序基础库 | `2.10.0+` | SDK 初始化会注册 `wx.onUnhandledRejection`,低于该版本的运行时不建议接入 |
| 推荐基础库 | `2.12.0+` | 可完整采集页面渲染、启动、脚本执行和 setData 更新耗时 |
| 微信开发者工具 | 使用近期稳定版 | 需要支持 npm 安装依赖并执行 **工具 > 构建 npm** |
| npm 包 | `@flashcatcloud/miniprogram-rum` | 包含核心能力、平台适配层和 RUM 入口 |
如果小程序允许用户在低于 `2.10.0` 的基础库中运行,SDK 初始化阶段可能无法注册未处理 Promise 拒绝监听。建议在小程序管理后台设置最低基础库版本,或在接入前根据业务覆盖范围评估低版本用户占比。
## 功能兼容性
| 功能 | 依赖能力 | 最低基础库 | 低版本表现 |
| ------------ | -------------------------------------------------------------- | --------- | --------------------------- |
| 页面生命周期采集 | 全局 `Page` 包装、`onLoad`、`onShow`、`onReady`、`onHide`、`onUnload` | 基础能力 | 受小程序页面生命周期能力限制 |
| 用户操作采集 | 页面事件处理函数包装 | 基础能力 | 受页面事件能力限制 |
| 网络请求采集 | `wx.request`、`wx.uploadFile`、`wx.downloadFile` | 基础能力 | 不支持对应 API 时无法自动采集该类型请求 |
| 错误采集 | `wx.onError`、`wx.onUnhandledRejection` | `2.10.0+` | 低版本不建议启用 SDK |
| 网络状态 | `wx.getNetworkType`、`wx.onNetworkStatusChange` | 基础能力 | 获取失败时会按默认连接状态处理 |
| 本地缓存 | `wx.setStorageSync`、`wx.getStorageSync`、`wx.removeStorageSync` | 基础能力 | 用于会话状态和失败 payload 重试 |
| 页面性能 | `wx.getPerformance` | `2.11.0+` | 不支持时不会采集 Performance API 指标 |
| setData 更新耗时 | 页面实例 `setUpdatePerformanceListener` | `2.12.0+` | SDK 会检测函数是否存在,不支持时跳过该指标 |
`trackPerformance` 默认开启,但性能相关 API 在源码中做了兼容处理。基础库不支持 `wx.getPerformance` 或页面实例不支持 `setUpdatePerformanceListener` 时,页面、操作、请求、错误等基础事件仍可继续采集。
## 支持的平台
| 平台 | 支持状态 | 说明 |
| -------------------- | ------ | --------------------------------------------------- |
| 微信小程序 | ✅ 支持 | SDK 面向微信小程序运行时设计 |
| 微信小游戏 | ❌ 不支持 | 当前 SDK 依赖小程序页面生命周期和 `Page` 包装 |
| 其他小程序平台 | ❌ 不支持 | 支付宝、百度、字节、QQ 等小程序平台 API 不在当前支持范围内 |
| uni-app / Taro 等跨端框架 | ⚠️ 需验证 | 如果最终产物运行在微信小程序并保留标准 `Page` 与 `wx.*` API,可在测试环境验证后接入 |
## 开发工具和构建要求
接入 npm 包时,需要在微信开发者工具中完成 npm 构建:
1. 在小程序项目根目录执行 `npm install @flashcatcloud/miniprogram-rum`
2. 在微信开发者工具中打开项目
3. 执行 **工具 > 构建 npm**
4. 确认生成的 `miniprogram_npm` 可以被小程序代码引用
本地验证兼容性时,可在微信开发者工具的本地设置中选择不同调试基础库版本,分别验证初始化、自动采集和数据上报行为。
## 相关页面
完成微信小程序 RUM SDK 安装和初始化。
配置代理、链路追踪、会话和手动埋点。
了解 SDK 自动采集的页面、操作、请求、错误和性能数据。
# 微信小程序 SDK 数据收集
Source: https://docs.flashduty.com/zh/rum/sdk/wechat-miniprogram/data-collection
了解微信小程序 RUM SDK 自动采集的页面、操作、请求、错误和性能数据
微信小程序 RUM SDK 初始化后,会通过小程序运行时 API 自动采集用户体验数据。你可以通过初始化参数关闭某类采集,也可以用手动 API 补充业务事件。
## 采集概览
| 数据类型 | 默认状态 | 采集来源 | 事件类型 |
| ----- | ---- | ---------------------------------------------------------------------------------------- | ---------- |
| 页面访问 | 开启 | `Page` 生命周期:`onLoad`、`onShow`、`onReady`、`onHide`、`onUnload` | `view` |
| 用户操作 | 开启 | 页面方法收到带有 `type` 的事件对象时自动记录 | `action` |
| 网络请求 | 开启 | `wx.request`、`wx.uploadFile`、`wx.downloadFile` | `resource` |
| 应用错误 | 开启 | `wx.onError`、`wx.onUnhandledRejection`、`wx.onPageNotFound`、`wx.onLazyLoadError` 和失败的网络请求 | `error` |
| 性能指标 | 开启 | `wx.getPerformance` 和页面 `setUpdatePerformanceListener` | `view` |
| 自定义事件 | 手动上报 | `addCustomEvent()` | `custom` |
## 通用事件属性
SDK 会在发送前为每条 RUM 事件补充应用、会话、页面、网络、用户和上下文信息。这些字段用于在查看器中关联同一个用户会话、同一个页面 view 以及同一次网络状态。
| 字段 | 说明 |
| ----------------------------- | -------------------------------------------- |
| `application.id` | RUM 应用 ID,来自初始化参数 `applicationId` |
| `session.id` | SDK 生成的会话 ID |
| `session.type` | 固定为 `user` |
| `session.has_replay` | 固定为 `false` |
| `session.sampled_for_replay` | 固定为 `false` |
| `source` | 固定为 `miniprogram` |
| `view.id` | 当前事件关联的页面 view ID |
| `view.name` / `view.url` | 当前事件关联的页面名称,默认来自小程序页面路由 |
| `connectivity.status` | 网络连接状态,包含 `connected` 或 `not_connected` |
| `connectivity.interfaces` | 网络类型,例如 `wifi`、`cellular`、`none` 或 `unknown` |
| `connectivity.effective_type` | 蜂窝网络类型,例如 `2g`、`3g`、`4g` |
| `usr` | 通过 `setUser()` 设置的用户信息,或 SDK 生成的匿名用户信息 |
| `context` | 通过 `setGlobalContext()` 设置的全局上下文 |
SDK 会通过 `wx.getNetworkType` 获取初始网络类型,并通过 `wx.onNetworkStatusChange` 更新后续事件的网络状态。
## 页面访问
启用 `trackPages` 后,SDK 会包装全局 `Page` 构造函数,并监听页面生命周期。每个页面会生成 view 事件,页面名称默认使用页面实例的 `route`。
SDK 会记录以下页面信息:
| 字段 | 说明 |
| ------------------------ | ----------------------------------------- |
| `view.id` | SDK 为页面生成的唯一 ID |
| `view.name` / `view.url` | 页面路由名称;无法获取时为 `unknown` |
| `view.referrer` | 上一个页面名称 |
| `view.loading_type` | 页面加载类型,包含 `initial_load` 或 `route_change` |
| `view.loading_time` | 从 `onLoad` 到 `onReady` 的耗时 |
| `view.time_spent` | 页面处于前台激活状态的累计时间 |
| `view.onload_to_onshow` | 从 `onLoad` 到首次 `onShow` 的耗时 |
| `view.onshow_to_onready` | 从首次 `onShow` 到 `onReady` 的耗时 |
| `view.action.count` | 当前 view 中关联的操作数量 |
| `view.error.count` | 当前 view 中关联的错误数量 |
| `view.resource.count` | 当前 view 中关联的资源请求数量 |
SDK 每 3 秒更新一次活跃页面的停留时长。页面进入后台、隐藏或卸载时,SDK 会发送带有 `hidden` 或 `terminated` 状态的 view 更新。
## 用户操作
启用 `trackActions` 后,SDK 会包装页面配置中的函数。当函数收到第一个参数,且该参数包含字符串类型的 `type` 字段时,SDK 会记录一次用户操作。
操作事件会包含以下信息:
| 字段 | 说明 |
| ----------------------- | ----------------------------------------------------------------------------------------- |
| `action.type` | 小程序事件类型,例如 `tap` |
| `action.target.name` | 取自 `event.currentTarget.dataset.name`、`dataset.content` 或 `dataset.type`;无法获取时为 `unknown` |
| `_dd.action.position` | 当事件包含坐标时,记录 `x` 和 `y` |
| `action.loading_time` | 操作后页面活动稳定所需时间 |
| `action.error.count` | 操作期间产生的错误数量 |
| `action.resource.count` | 操作期间产生的资源请求数量 |
为可点击组件设置 `data-name` 可以让操作名称更容易识别,例如 `提交订单 `。
## 网络请求
启用 `trackRequests` 后,SDK 会包装 `wx.request`、`wx.uploadFile` 和 `wx.downloadFile`。SDK 上报自身数据的 intake 请求和标记为内部请求的调用会被跳过,避免产生循环采集。
网络请求会生成 resource 事件:
| 字段 | 说明 |
| ---------------------------------------- | --------------------------------------------------- |
| `resource.type` | `xhr`、`upload` 或 `download` |
| `resource.url` | 请求 URL |
| `resource.method` | 请求方法;`wx.request` 默认 `GET`,上传固定为 `POST`,下载固定为 `GET` |
| `resource.status_code` | 请求成功时的 HTTP 状态码 |
| `resource.duration` | 请求耗时 |
| `resource.error_message` | 请求失败时的错误信息 |
| `resource.trace_id` / `resource.span_id` | 启用分布式追踪并命中采样时生成的链路标识 |
## 错误采集
启用 `trackErrors` 后,SDK 会订阅小程序应用错误、未处理 Promise 拒绝、页面不存在和分包懒加载失败事件,并把失败的网络请求同时记录为错误。
| 来源 | SDK 标记 | 说明 |
| ------------------------- | ---------------- | ----------------------------------- |
| `wx.onError` | `app` | 小程序运行时错误 |
| `wx.onUnhandledRejection` | `promise` | 未处理的 Promise 拒绝 |
| `wx.onPageNotFound` | `page-not-found` | 打开的页面不存在 |
| `wx.onLazyLoadError` | `lazy-load` | 分包懒加载失败 |
| 网络请求失败 | `network` | 请求失败时,SDK 在 resource 事件之外额外生成一条错误事件 |
| `addError()` | `custom` | 你手动上报的业务错误 |
错误事件会包含错误消息、可选堆栈和来源。手动上报错误时,可以把 `error.stack` 作为第三个参数传入 `addError()`。
## 性能指标
启用 `trackPerformance` 后,SDK 会读取小程序性能 API。运行时支持对应 API 时,SDK 会把性能指标写入 view 事件。
| 指标 | 说明 |
| -------------------------------- | -------------------------------------------- |
| `view.app_launch` | 小程序启动耗时,来自 `navigation` 类型的 `appLaunch` 记录 |
| `view.evaluate_script` | 主包脚本执行耗时,来自 `script` 类型的 `evaluateScript` 记录 |
| `view.first_render` | 页面首屏渲染耗时,来自 `render` 类型的 `firstRender` 记录 |
| `view.first_render_detail` | 首屏渲染拆分指标,包括视图层准备、初始数据发送、初始数据接收、渲染开始和渲染结束 |
| `view.performance.fcp.timestamp` | First Contentful Paint 时间 |
| `view.performance.lcp.timestamp` | Largest Contentful Paint 时间 |
| `view.setdata.count` | 当前 view 中 `setData` 更新次数 |
| `view.setdata.duration` | 当前 view 中 `setData` 更新累计耗时 |
如果当前小程序基础库不支持 `wx.getPerformance` 或 `setUpdatePerformanceListener`,SDK 会跳过对应指标,不会影响其他数据采集。
## 自定义事件
调用 `addCustomEvent(name, context?)` 会生成 custom 事件。你可以用它记录无法从页面生命周期、操作或请求中自动推断的业务事件。
| 字段 | 说明 |
| --------------- | ---------- |
| `event.name` | 自定义事件名称 |
| `event.context` | 自定义事件上下文对象 |
```javascript pages/order/detail.js theme={null}
import { flashcatRum } from "@flashcatcloud/miniprogram-rum";
flashcatRum.addCustomEvent("order_status_changed", {
orderId: "order-123",
status: "paid"
});
```
## 事件关联
SDK 会把非 view 事件关联到事件发生时间对应的页面和会话:
* 页面事件用于建立当前 view,并定期更新页面停留时长
* action、resource 和 error 事件会增加当前 view 的计数
* 如果事件发生时当前会话已过期,SDK 会创建新会话
* 历史 view 更新和延迟产生的事件会优先按事件时间查找对应页面,避免归属到错误页面
## 关闭某类自动采集
你可以在初始化时关闭不需要的采集类型:
```javascript app.js theme={null}
import { flashcatRum } from "@flashcatcloud/miniprogram-rum";
flashcatRum.init({
applicationId: "",
clientToken: "",
trackActions: false,
trackRequests: false,
trackPerformance: false
});
```
关闭某类自动采集只影响对应的自动监听逻辑。手动 API 仍可使用,例如关闭 `trackActions` 后,你仍然可以调用 `addAction()` 上报自定义操作。
## 上报批次
SDK 会把采集到的 RUM 事件加入批次后发送:
| 配置 | 值 |
| -------- | --------------------------------- |
| 默认刷新间隔 | `15000` 毫秒,可通过 `flushInterval` 调整 |
| 单批最大消息数 | `50` |
| 单批最大大小 | `64 KB` |
| 单条消息最大大小 | `256 KB` |
| 后台刷新 | 小程序触发 `onAppHide` 时会刷新批次 |
未发送成功的 payload 会通过小程序存储能力持久化,并在下次启动批量上报模块时重新发送。SDK 最多保留 `10` 个待重试 payload,总大小不超过 `64 KB`,超过 `24` 小时的 payload 会被丢弃。
## 相关页面
完成微信小程序 RUM SDK 安装和初始化。
配置代理、链路追踪、会话和手动埋点。
了解小程序基础库版本、开发工具和平台 API 要求。
# SDK 接入指南
Source: https://docs.flashduty.com/zh/rum/sdk/wechat-miniprogram/sdk-integration
在微信小程序中接入 RUM SDK,采集页面、操作、请求、错误和性能数据
微信小程序 RUM SDK 通过 `@flashcatcloud/miniprogram-rum` 提供 `flashcatRum` 实例。初始化后,SDK 会自动采集页面生命周期、用户操作、网络请求、应用错误和性能指标,并上报到 Flashduty RUM。
## 前提条件
在接入 SDK 前,请先完成以下准备:
* 在 Flashduty 控制台创建或选择一个 RUM 应用,并获取 **Application ID** 和 **Client Token**
* 确认小程序可以访问 RUM 数据上报地址。默认地址为 `https://browser.flashcat.cloud/api/v2/rum`;如果你的网络策略需要转发,请配置 `proxy`
* 在微信公众平台配置 request 合法域名:进入 **开发 > 开发管理 > 开发设置 > 服务器域名**,将 `https://browser.flashcat.cloud`(或你的代理域名)添加到 **request 合法域名**。未配置时,真机上的所有上报请求会被微信拦截;开发调试阶段可临时勾选微信开发者工具的「不校验合法域名」选项
* 如果使用微信开发者工具,请在工具中构建 npm,使 `miniprogram_npm` 可以引用 SDK 包
## 安装 SDK
在小程序项目根目录安装 RUM SDK:
```bash theme={null}
npm install @flashcatcloud/miniprogram-rum
```
安装后,在微信开发者工具中执行 **工具 > 构建 npm**。
## 初始化 SDK
在小程序入口文件中尽早初始化 SDK。SDK 会在初始化时包装小程序的页面生命周期、请求方法和应用错误监听,所以建议在 `app.js` 中完成初始化。
```javascript app.js theme={null}
import { flashcatRum } from "@flashcatcloud/miniprogram-rum";
flashcatRum.init({
applicationId: "",
clientToken: "",
service: "wechat-miniprogram",
env: "production",
version: "1.0.0",
sessionSampleRate: 100
});
```
请不要在客户端代码中使用服务端密钥。`clientToken` 是用于客户端数据上报的令牌,`applicationId` 是 RUM 应用标识。
## 初始化参数
### 必填参数
RUM 应用 ID。事件上报时会写入 `application.id`,用于将小程序数据归属到对应应用。
客户端上报令牌。SDK 会将该值作为 `dd-api-key` 参数附加到 RUM 上报请求中。
### 基础可选参数
RUM 数据接收站点。未配置 `proxy` 时,SDK 会将事件发送到 `https://{site}/api/v2/rum`。
自定义上报代理。字符串形式会生成 `{proxy}?ddforward={encodedPath}`;函数形式会接收 `{ path, parameters }` 并返回完整上报 URL。
服务名称。SDK 会将该值写入 `service:` 标签,便于在 RUM 中按服务筛选。
环境标识。SDK 会将该值写入 `env:` 标签,例如 `production`、`staging`。
应用版本。SDK 会将该值写入 `version:` 标签,用于按发布版本分析错误和性能。
会话采样率,取值表示要采集的会话百分比。`100` 表示全部采集,`0` 表示不采集会话事件。
在线上环境通常建议设置较小的采样率(如 `10` 表示采样 10%),降低存储开销。
批量上报间隔,单位为毫秒。SDK 默认每 15 秒尝试刷新一次事件批次,也会在小程序进入后台时触发刷新。
事件发送前的回调。返回 `false` 时,当前事件不会发送到 Flashduty。
启用调试日志。开启后,SDK 会在控制台输出初始化、监控启动、事件采集和批量上报信息。
是否为未设置用户信息的会话生成匿名用户 ID。启用后,SDK 会在 `usr.id` 和 `usr.anonymous_id` 中写入匿名 ID。
## 采集开关
以下开关用于控制自动采集能力,默认都处于开启状态:
| 参数 | 类型 | 默认值 | 说明 |
| ------------------ | ------- | ------ | ------------------------------------------------------------------- |
| `trackPages` | boolean | `true` | 采集页面生命周期并生成 view 事件 |
| `trackActions` | boolean | `true` | 采集页面事件处理函数中的用户操作并生成 action 事件 |
| `trackRequests` | boolean | `true` | 采集 `wx.request`、`wx.uploadFile` 和 `wx.downloadFile` 并生成 resource 事件 |
| `trackErrors` | boolean | `true` | 采集 `wx.onError`、`wx.onUnhandledRejection`、页面不存在、分包加载失败和网络请求失败产生的错误 |
| `trackPerformance` | boolean | `true` | 通过 `wx.getPerformance` 采集页面渲染、启动和脚本执行指标 |
## 使用用户信息和全局上下文
登录后,你可以使用 `setUser()` 关联当前用户。SDK 会把这些字段写入后续 RUM 事件的 `usr` 对象。
```javascript app.js theme={null}
flashcatRum.setUser({
id: "user-123",
name: "Alice",
email: "alice@example.com"
});
```
你也可以使用 `setGlobalContext()` 添加业务上下文。全局上下文会写入后续事件的 `context` 字段。
```javascript app.js theme={null}
flashcatRum.setGlobalContext({
tenant: "acme",
release_channel: "stable"
});
```
## 手动上报事件
除了自动采集,你还可以主动补充业务事件、错误、操作和自定义耗时。
```javascript pages/order/detail.js theme={null}
import { flashcatRum } from "@flashcatcloud/miniprogram-rum";
Page({
onPayTap() {
flashcatRum.addAction("pay_button_tap", "tap");
try {
// 执行业务逻辑
} catch (error) {
flashcatRum.addError(error.message, "custom", error.stack);
}
},
onCouponLoaded(couponId) {
flashcatRum.addCustomEvent("coupon_loaded", { couponId });
flashcatRum.addTiming("coupon_loaded");
}
});
```
| 方法 | 说明 |
| ------------------------------------ | --------------------------------------- |
| `addAction(name, type?)` | 手动上报操作事件,默认类型为 `custom` |
| `addError(message, source?, stack?)` | 手动上报错误事件,公开 API 的 `source` 固定为 `custom` |
| `addTiming(name, time?)` | 在当前页面 view 上记录自定义耗时,名称中的非法字符会替换为 `_` |
| `addCustomEvent(name, context?)` | 上报自定义事件,并附带可选上下文 |
| `startPage(name?)` | 手动开始一个页面 view,用于覆盖自动页面名称或记录虚拟页面 |
| `stopSession()` | 清除当前会话,下一次事件会创建新会话 |
| `getInitConfiguration()` | 返回最近一次初始化时传入的配置 |
## 下一步
配置代理、分布式追踪、会话和手动埋点。
了解小程序基础库版本、开发工具和平台 API 要求。
了解 SDK 自动采集的事件类型、字段和平台 API。
# 会话重放功能概览
Source: https://docs.flashduty.com/zh/rum/session-replay/overview
掌握 Flashduty RUM 的会话重放功能,通过重现用户操作路径快速定位问题并优化用户体验。
Flashduty RUM 的**会话重放功能**(Session Replay)是一款强大的用户行为分析工具,旨在帮助开发者通过重现用户在网站或应用中的操作路径,结合 RUM 性能和异常追踪数据,可直观了解用户体验,快速定位问题根因。
## 核心功能
自动记录用户的鼠标点击、页面滚动、表单输入、导航行为等操作,生成直观的会话回放视频
将会话重放与异常追踪结合,自动关联异常发生时的用户操作和页面状态
提供用户交互时间线,展示操作序列、页面加载时间以及关键事件的发生点
提供灵活的隐私配置,可屏蔽敏感信息或限制录制范围,确保数据合规性
## 价值与优势
| 优势 | 描述 |
| ---------- | -------------------------------- |
| **直观问题定位** | 通过可视化回放,快速了解用户遇到问题的具体操作路径,减少排查时间 |
| **提升用户体验** | 洞察用户行为模式,发现交互痛点,优化页面设计和功能逻辑 |
| **数据驱动优化** | 结合异常数据和用户行为分析,为产品迭代提供可靠的数据支持 |
## 使用场景
通过重放用户会话,复现异常发生时的操作场景,快速定位问题根源。
分析用户在关键页面(如支付、注册)的行为,优化用户体验和转化率。
结合异常追踪,识别页面加载慢、交互卡顿等问题,优化前端性能。
通过回放用户会话,快速了解用户反馈的问题,提供更精准的支持。
## 会话重放流程
在录制阶段,录制 SDK 会将当前 DOM 和 CSS 样式打快照,并在用户行为(DOM 变化、鼠标移动、点击、表单输入等)发生时收集对应的事件。通过序列化、压缩、去除敏感信息后进行数据上报。
Flashduty RUM 提供丰富的行为数据和分析工具,帮助定位问题并优化体验。
### 核心行为数据
| 数据类型 | 说明 |
| --------- | ----------------------- |
| **用户交互** | 点击、滚动、输入、导航等操作的时间线 |
| **页面性能** | 页面加载时间、资源加载失败、API 调用延迟等 |
| **异常上下文** | 异常发生时的页面状态、DOM 结构和用户操作 |
### 上下文信息
* **用户环境**:浏览器、设备、操作系统、网络状况
* **操作路径**:用户在会话中的完整操作序列
* **页面快照**:异常发生时的页面 DOM 快照
### 问题类型与定位
| 问题类型 | 典型表现 | 可能原因 | 定位方法 |
| ---------- | ---------- | --------------- | ----------- |
| **页面加载慢** | 页面白屏、加载超时 | 资源加载失败、网络延迟 | 查看是否有资源加载异常 |
| **功能失效** | 按钮点击无反应 | 代码逻辑错误、事件绑定问题 | 查看具体行为和异常 |
| **表单提交失败** | 数据未保存、提交失败 | API 响应错误、表单验证问题 | 查看错误和异常详情 |
## 问题分析工具
在播放器中,您可以查看用户的所有操作,包括点击、滚动和输入等,支持快进、回放和 seek 等播放行为控制,帮助开发者直观复现问题场景并精准分析用户行为。
会话回放支持与各类事件(如视图加载、错误、用户行为)关联,允许查看详细的 errors 和 attributes(上下文信息,如设备类型、浏览器版本、地理位置等),方便定位问题根因并进行深入分析。
## 下一步
配置会话重放采集
学习如何查看重放记录
了解隐私保护设置
# 隐私保护
Source: https://docs.flashduty.com/zh/rum/session-replay/privacy-protection
通过配置文本、输入框和页面元素的隐私级别,保护 Flashduty RUM 会话重放中的敏感数据。
为满足不同场景的隐私需求,会话重放功能内置了灵活的隐私保护策略。通过配置 `defaultPrivacyLevel` 字段,开发者可控制数据采集的敏感度,支持从显示所有文本(除密码外)到完全隐藏页面文本的多种模式,确保用户数据的安全性和合规性。
input 类型为 password 的输入为敏感信息,**所有场景都不会收集**。
## 隐私策略
配置 `defaultPrivacyLevel: "mask"` 将完全隐藏页面中的所有文本内容,仅保留操作行为和页面结构,适合对数据隐私要求较高的场景。
```javascript theme={null}
window.FC_RUM.init({
applicationId: "YOUR_APPLICATION_ID",
clientToken: "YOUR_CLIENT_TOKEN",
// ...
sessionReplaySampleRate: 10,
defaultPrivacyLevel: "mask",
// ...
});
```
配置 `defaultPrivacyLevel: "mask-user-input"` 将隐藏用户输入框中的内容(如文本输入、选择框等),但保留页面其他文本,适用于需要保护用户输入隐私的场景。
```javascript theme={null}
window.FC_RUM.init({
applicationId: "YOUR_APPLICATION_ID",
clientToken: "YOUR_CLIENT_TOKEN",
// ...
sessionReplaySampleRate: 10,
defaultPrivacyLevel: "mask-user-input",
// ...
});
```
配置 `defaultPrivacyLevel: "allow"` 允许采集页面中除密码字段外的所有文本内容,适合需要完整用户交互细节的场景。
```javascript theme={null}
window.FC_RUM.init({
applicationId: "YOUR_APPLICATION_ID",
clientToken: "YOUR_CLIENT_TOKEN",
// ...
sessionReplaySampleRate: 10,
defaultPrivacyLevel: "allow",
// ...
});
```
## 配置对比
| 配置值 | 页面文本 | 输入框内容 | 密码字段 | 适用场景 |
| ----------------- | ---- | ----- | ---- | ------- |
| `mask` | 隐藏 | 隐藏 | 隐藏 | 高隐私要求场景 |
| `mask-user-input` | 显示 | 隐藏 | 隐藏 | 保护用户输入 |
| `allow` | 显示 | 显示 | 隐藏 | 完整交互细节 |
# SDK 配置
Source: https://docs.flashduty.com/zh/rum/session-replay/sdk-config
配置 Flashduty RUM 会话重放的采样比例与隐私规则,安全记录用户会话。
Flashduty RUM 的会话重放功能集成于 RUM SDK 中,通过简单配置采样比例和隐私规则,即可快速启用重放功能。
## 开启采集
重放 SDK 已集成至 RUM SDK,配置采样比例便可开启重放功能:
```javascript theme={null}
window.FC_RUM.init({
applicationId: "YOUR_APPLICATION_ID",
clientToken: "YOUR_CLIENT_TOKEN",
// ...
sessionReplaySampleRate: 10, // 默认会话重放的 session 采样率 10%
// ...
});
```
**采样方式**:在客户端 SDK 初始化 session 时生成 0-1 之间的随机数,与 `rate/100` 进行大小比较。如落在区间内,则该 session 会作为采集样本,回放数据会在 session 周期内采集与上报。
在 session 被采样的基础上,会话重放的采样率(sessionReplaySampleRate)会被进行二次计算和采样。
默认配置采样率后,会在 `RUM.init()` 执行后开启自动采集。若想手动控制采集时机(如用户登录后再进行数据采集),可先开启手动采集开关,再手动调用 record 方法:
```javascript theme={null}
window.FC_RUM.init({
applicationId: "YOUR_APPLICATION_ID",
clientToken: "YOUR_CLIENT_TOKEN",
// ...
sessionReplaySampleRate: 10, // 采样率 10%
startSessionReplayRecordingManually: true, // 开启手动采集开关
// ...
});
if (userIsShouldRecord()) {
// 如果满足某些条件,可开启回放
window.FC_RUM.startSessionReplayRecording(); // 在调用时再开启数据采集
}
```
开启采集后,可通过 `stopSessionReplayRecording()` 方法停止采集。
在某些场景下,即使采样率并未命中,也希望采集该 session 相关数据(如重点监测刚上线的功能,或者捕获某个异常后希望上报后续操作),此时可以通过调用 `startSessionReplayRecording({ force: true })` 方法来强制开启重放。
只有当本次 session 被采样,而 sessionReplay 未被采样的情况下,强制开启才会生效。如果 session 本身并没有被采样,即使强制开启 replay 也无效。
## 关闭采集
如果需要关闭采集功能,将对应的 replay 采样率调整至 0 或者直接去掉该配置项即可:
```javascript theme={null}
window.FC_RUM.init({
applicationId: "YOUR_APPLICATION_ID",
clientToken: "YOUR_CLIENT_TOKEN",
// ...
sessionReplaySampleRate: 0, // 关闭重放功能
// ...
});
```
## 工作原理
会话重放 SDK 基于 [rrweb](https://www.rrweb.io/) 实现。
录制 SDK 会将当前 DOM 和 CSS 样式打快照,并在用户行为(DOM 变化、鼠标移动、点击、表单输入等)发生时收集对应的事件。通过序列化、压缩、去除敏感信息后进行数据上报。
播放 SDK 会根据快照进行 DOM 重建,并在合适的时机将事件行为转换为 DOM 变化并进行展示。
* 在数据上报前,SDK 会提前进行数据压缩,并将该 CPU 密集操作放在 Web Worker 中执行,不会影响主线程渲染
* SDK 兼容性和 RUM SDK 一致,支持 IE11 以上浏览器
## 下一步
学习如何查看重放记录
了解隐私保护设置
# 重放记录
Source: https://docs.flashduty.com/zh/rum/session-replay/session-viewing
查看并筛选 Flashduty RUM 会话重放记录,重现用户操作路径并排查性能与异常问题。
Flashduty RUM 的会话重放功能通过直观地重现用户操作路径,帮助开发者快速定位问题、分析用户行为并优化产品体验。集成于 RUM SDK 中,只需简单配置即可启用,支持灵活的采样策略和隐私规则设置。
## 会话列表
在「会话重放」菜单中,您可以查看最近的会话记录,默认按时间倒序排列。
**支持的功能:**
* 按会话时长、视图数量、行为数量、异常数量等字段排序
* 丰富的筛选条件(如时间范围、页面、标签等)
点击任一记录项,将打开播放器面板:
| 区域 | 说明 |
| --------- | -------------------------- |
| **信息展示区** | 展示会话的访问时间、起始与结束页面、标签等上下文信息 |
| **播放区** | 以用户视角重现操作路径,清晰展示用户交互细节 |
| **播放控制区** | 提供播放控制功能,方便操作 |
为方便快速浏览,列表中仅展示持续时间**大于 3 秒**的回放。
## 播放器
播放器支持播放、暂停、快进、快退、重播、倍速播放、全屏和 Seek 等功能,并支持快捷键操作,提升使用效率。
播放过程中,时间轴上会以不同颜色的图标标记用户行为(Action)和异常(Error),便于快速概览会话中的关键事件。
默认情况下,播放器会自动跳过非活跃片段以提高查看效率。您也可以通过配置关闭此功能,按实际时序完整播放。
## Devtools
通过「查看全部事件和异常」功能,可进入宽屏模式,查看会话的操作时间线和详细分析。
展示会话中的所有用户操作,支持以下功能:
* 切换相对时间与绝对时间显示
* 按事件类型筛选(如点击、页面跳转等)
* 点击具体事件,播放器将自动跳转至对应时间戳
列出会话中的所有异常和问题,支持点击跳转至详细错误信息,便于快速定位和分析。
展示会话期间所有网络请求的详细信息,帮助您分析资源加载和 API 调用情况。
**支持的功能:**
* 按资源类型筛选:默认选中 XHR 和 Fetch 请求,也可查看 Image、JS、CSS、Font、Document、Media 等静态资源类型
* 切换相对时间与绝对时间显示
* 按状态码或 URL 搜索请求记录。状态码搜索支持高级语法,例如 `200`(匹配成功请求)、`-200`(排除 200)、`>=400`(匹配错误请求)、多条件组合(如 `-200 -202`)
* 点击任意请求记录,可打开资源详情侧栏查看完整的时序信息
每条请求记录展示以下字段:
| 字段 | 说明 |
| --- | ----------------------- |
| 时间 | 请求发生的时间 |
| 状态码 | HTTP 响应状态码 |
| 类型 | 资源类型(XHR、Fetch、Image 等) |
| 方法 | HTTP 请求方法(GET、POST 等) |
| URL | 请求的完整地址 |
| 大小 | 响应体大小 |
展示会话的上下文信息(如设备、浏览器、地理位置等),帮助开发者深入了解问题背景并进行精准定位。
## 下一步
了解隐私保护设置
# Agent
Source: https://docs.flashduty.com/zh/ai-sre/agents
Agent 资源让 AI SRE 接入外部 Agent 生态。当前支持 A2A(Agent-to-Agent)类型——既可把任务委派给远端 Agent,也能对外暴露 Agent Card 供外部客户端反向调用,用于故障 / 作战室联动与双向事件流。
**公测功能**:AI SRE 已全量开放公测,无需申请,登录控制台即可直接使用,公测期间免费。功能与界面可能继续调整。
## 概述
***
**Agent** 是把 AI SRE 接入外部 Agent 生态的资源类别。当前支持的类型是 **A2A(Agent-to-Agent)**——一套让不同 Agent 相互调用的标准协议(后续可能扩展更多 Agent 类型)。A2A 把 AI SRE 接入外部 Agent,有两个方向:
在列表中注册的**远端 A2A Agent**。AI SRE 通过标准 A2A 协议把任务**委派**给它们——例如一个专精指标分析、或对接某个内部系统的外部 Agent。
本平台的 AI SRE 自身也是一个 A2A Agent,对外暴露一张 **Agent Card**。外部 A2A 客户端把该 Card 地址填入即可**反向调用** Flashduty 的 AI SRE,用于故障 / 作战室联动与双向事件流。
委派后无需等待:AI SRE 把任务交给远端 Agent 后会立即继续当前对话,您可以继续工作或同时委派多个任务;远端完成后,其结果作为一条新消息出现在对话中。每次 A2A 委派在对话流里以一张**任务卡片**呈现,卡片带 `A2A` 徽标,显示远端 Agent 名、本次任务意图、运行状态(初始化 / 进行中 / 完成 / 失败 / 中断)以及工具调用数、Token、耗时等用量;点击卡片可在右侧面板里查看该次委派的完整过程。
**调用说明分两层,是 Agent 选择信号**。AI SRE 委派前看到的「可用 Agent 清单」里,每一项只有 `名称:简介`——简介来自调用说明开头的 `summary:` 一行(不写则自动截取正文开头),AI SRE 靠它判断**要不要、什么时候**把任务派给这个 Agent,务必写清楚何时优先选用它、擅长什么、不适合做什么。简介之后的正文不会常驻清单,只在**首次委派给这个 Agent 时**才完整送达——放心写长、写细(操作步骤、硬性规则、示例),不会拖慢日常对话。写法详见下文「[调用说明的写法](#调用说明的写法)」。
A2A Agent 的列表与管理入口在 **插件 → Agents** 页面(菜单标签为 **Agents**)。
**Agents 涵盖两类不同的概念。** 本页(Agents)当前管理的是 **A2A Agent**(外部 Agent 互调)。另一类是 **Subagent(任务子代理)**——平台内置、由 AI SRE 在会话中按需派发的任务执行器,没有创建 / 编辑入口,只能在会话中观察其行为,详见下文「[Subagent 任务子代理](#subagent-任务子代理)」。
## Subagent 任务子代理
***
**Subagent** 是平台**内置**的任务执行器。AI SRE 在排障过程中,可以把一个自包含的子任务\*\*派发(dispatch)\*\*给一个 Subagent 去独立完成——派发统一通过单一的长时运行工具 `agent_dispatch` 进行,而不是为每个 Subagent 生成一个独立工具。
平台预置了若干**引导(bootstrap)Subagent**,开箱即用:
| 名称 | 角色 |
| --------- | --------------------------------------------------------------------------------- |
| `general` | 通用执行器,拥有完整工具权限,适合把中间步骤会污染主对话上下文的工作(长报告、多文件改动、端到端构建、反复探查)整体外包出去;可并行派发多个处理相互独立的工作单元 |
| `explore` | 只读调查器,仅限 `grep` / `glob` / `read`,不能写入或执行;返回浓缩摘要而非原始搜索输出,适合在代码库或知识转储中定位证据 |
**会话中的呈现**:每次派发在对话流里同样以一张**任务卡片**呈现,与 A2A 委派共用同一套状态生命周期(初始化 / 进行中 / 完成 / 失败 / 中断)。区别在于徽标——Subagent 任务卡片带 `Agent` 徽标,而 A2A 委派带 `A2A` 徽标。
**运行约束**:
* **并发上限**:每个会话**最多同时运行 20 个 Subagent**(`TaskMaxConcurrentPerSession = 20`)。这里限制的是「同一时刻并发运行」的数量而非会话累计派发数——每完成一个就释放一个名额,因此会话整体可完成的工作量不受限。达到上限时再派发会报错(`too many active subagents (… running, limit 20)`),提示模型先停下等待运行中的任务完成、再派发其余的。
* **嵌套深度**:派发链**最多嵌套 3 层**(`TaskMaxNestingDepth = 3`),防止 Subagent 无限自我派生。
**Subagent 目前没有面向用户的创建 / 管理界面。** 它是一项内置运行能力:您可以在会话中观察 Subagent 任务卡片及其子会话过程,但无法像 A2A Agent 那样新增、编辑或删除 Subagent。本页(Agents)当前管理的仅是 A2A Agent。
## 注册出站 A2A Agent
***
在 A2A Agents 列表页点击 **添加 A2A Agent**,在表单中填写:
| 字段 | 类型 | 默认值 | 说明 |
| --------------------- | ----------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 名称 | string | — | A2A Agent 标识(如 `metrics-analyzer`)。必填 |
| 范围 | 账户 / 团队 | — | 作用域:**账户**(账户内全局可见)或某个**团队**(仅该团队成员可见和可编辑)。必填,详见下文「作用域」 |
| 执行环境 | 云端环境 / BYOC Runner(可多选) | 所有环境 | 决定该 A2A Agent 在哪些执行环境中可用。可以选择云端环境和一个或多个当前可见的 BYOC Runner;不选择时默认在所有环境可用。它不指定委派调用路由:A2A 调用仍在当前 AI SRE 会话自身的执行环境中运行。若远端 Agent 只在某个内网可访问,请只选择能访问它的 Runner |
| 调用说明 | string | — | 面向 AI SRE 的 Agent 选择信号,是**一份文档**:可选的 `summary:` frontmatter + 正文。简介(`summary`)进入「可用 Agent 清单」,正文在首次委派时才完整送达。必填;整份文档最多 50 KB,`summary` 最多 1,024 个字符且不能包含 `<` `>`。写法见下文「[调用说明的写法](#调用说明的写法)」 |
| Card URL | string | — | 远端 A2A Agent 的 Agent Card 地址,或仅填写遵循默认 well-known 规则的服务根地址(如 `https://agents.example.com`)。如果 URL 已带路径,平台会按该地址原样读取;如果只填服务根地址,平台按 A2A 约定查找 `/.well-known/agent-card.json`。必填。平台只校验 URL 格式合法(scheme 为 http/https、host 非空),不做主机或 IP 分类;实际的网络可达性与出站限制取决于发起委派的 AI SRE 会话所在执行环境,上面的执行环境字段只限制该 Agent 在哪些环境中可用 |
| 认证类型 | enum | `none` | 出站请求附带的凭证类型:`none`(无)/ `bearer`(Bearer Token)/ `api_key`(自定义 Header + Key) |
| 流式传输 | bool | 开 | 是否以流式方式与远端交互 |
| 用户级认证模式 | enum | `shared` | 见下表「认证模式」 |
| 跳过 TLS 证书校验 | bool | 关 | 仅当 Card URL 为 HTTPS 时显示。只在远端使用自签证书且网络受控时开启;开启后会跳过证书链和主机名校验 |
| 允许通过 HTTP 进行 OAuth 发现 | bool | 关 | 仅当选择「每用户 OAuth」且 Card URL 是非本地 HTTP 地址时需要确认。只用于受控测试环境;开启后 AI SRE 服务端会访问该主机的 OAuth metadata |
### 调用说明的写法
调用说明是**一份文档**,最多分两部分:开头一段可选的 YAML frontmatter(只有一个 `summary` 字段),后面是正文。
```yaml theme={null}
---
summary: 一句话简介,AI 据此决定是否派发
---
正文:给 AI 的详细调用说明……
```
* **简介(`summary`)驱动路由**:AI SRE 每次决定要不要委派时,看到的只是「可用 Agent 清单」里的一行 `名称:简介`。简介就是这一行的内容,务必写清楚**什么时候该优先选它、擅长什么、不擅长什么**——用具体的能力词(产品名、动词、场景),不要写空泛的宣传语。简介过长会在清单里被截断,重要信息往前写。
* **正文按需送达,不常驻清单**:正文不会一直占着 AI SRE 的上下文;只有当 AI SRE **第一次把任务委派给这个 Agent** 时,正文才会完整发给它(渐进式加载)。这意味着正文可以放心写得很长、很细——操作步骤、硬性规则(HARD RULE)、示例——不用担心拖慢日常对话。
* **不写 `summary` 也兼容**:如果调用说明整段是纯文本、不以 `---` 开头,全部内容都会被当作正文,AI SRE 自动截取开头一段作为简介(会被截断),旧版本写的调用说明无需改动即可继续用。但强烈建议显式写一段 `summary`,路由效果更可控。
* **硬性限制**:整份调用说明(frontmatter + 正文)不超过 **50 KB**;`summary` 不超过 **1,024 个字符**,且不能包含 `<` 或 `>`;正文不能为空。
* 如果开头写了 `---`,就必须再用一行 `---` 把 frontmatter 闭合,否则保存会失败。
下文「[使用 FlashAI 模板](#使用-flashai-模板)」的调用说明就是一份实际生效的范例,可以参考它的结构。
### 使用 FlashAI 模板
**FlashAI** 是 Flashcat / 快猫星云体系内的可观测分析产品,也可以作为远端 A2A Agent 供 AI SRE 调用。在 A2A Agents 页面展开 **连接 FlashAI 可观测分析** 折叠卡片,即可使用 FlashAI 模板创建 A2A Agent。
FlashAI 模板的定位不是「所有可观测查询都走 FlashAI」,而是把 FlashAI 配置为 **Flashcat / 快猫星云来源告警与故障排查** 的委派目标。对于来自 Flashcat 的事件墙 / Event Wall、灭火图 / Firemap、北极星 / Polaris 等告警或故障,AI SRE 应优先把分析任务委派给 FlashAI。
模板默认预填一份调用说明文档,开头是一行 `summary:` 简介:
```yaml theme={null}
summary: Flashcat/快猫星云 observability & ops — Firemap 灭火图, Polaris 北极星/northstar, logs 日志检索/报表, metrics 指标, traces 链路/拓扑, inspections 巡检/拨测, alert rules & dashboards. Call for ANY Flashcat task; MUST dispatch first whenever integration_type is "n9e.alert".
```
这行简介会出现在 AI SRE 的「可用 Agent 清单」里,是 FlashAI 被优先选中的直接原因;summary 之后是正文,核心路由规则如下:
* 用户正在排查明确来自 Flashcat / 快猫星云的告警、故障、事件或告警组时,优先调用 FlashAI。
* 事件墙 / Event Wall 上的告警事件、故障和告警组属于正向触发信号。
* 灭火图 / Firemap 故障属于正向触发信号,常见字段包括 `fault_type=firemap` 或 `rule_prod=firemap`。
* 北极星 / Polaris 故障属于正向触发信号,常见字段包括 `fault_type=polaris`、`rule_prod=polaris` 或内部标识 `rule_prod=northstar`。
* 来自 `n9e.alert` 的 Flashcat 告警如果带有 `rule_prod`、`rule_config.detail_url`、`workspace`、`fault_type`、`fault_workspace`、`fault_detail_url`、`fault_condition` 等故障元数据,也应优先委派给 FlashAI。
* 如果用户只是泛泛询问 metrics、logs、traces、topology 或性能问题,但没有 Flashcat / 快猫星云告警上下文、URL、产品标识或上述故障字段,不应默认调用 FlashAI;应使用当前可用工具或客户实际接入的可观测数据源。
FlashAI 侧需要先完成以下配置:
FlashAI 需为 `release-24` 或更新版本。
在 FlashAI / Flashcat 控制台打开 `/config` 页面(例如 `https://demo.flashcat.cloud/config`),添加 `a2a_server_base_url`,值填写当前 FlashAI 的访问域名,例如 `https://demo.flashcat.cloud`。
如果 FlashAI 使用内网地址,只有部署在该网络内的 BYOC Runner 可以访问;如果希望云 Sandbox 也能调用 FlashAI,请使用公网可达域名,并按需配置白名单。这个限制与 MCP SSE 地址在 Sandbox 中的网络可达性要求一致。
完成 FlashAI 侧配置后,在折叠卡片中填写 **FlashAI 域名**(例如 `demo.flashcat.cloud`),点击 **使用此模板**。页面会打开 **添加 A2A Agent** 表单并预填:
* 名称:根据域名生成,例如 `flashai-demo`
* 调用说明:开头一行 `summary:` 简介 + 正文,正文列出哪些 Flashcat 告警/故障应优先调用 FlashAI、哪些泛化可观测问题不应调用。
* Card URL:根据域名自动生成:
```text theme={null}
https://demo.flashcat.cloud/api/fc-model/a2a/.well-known/agent-card.json
```
模板只负责预填通用信息;你仍需在表单中选择**范围**(账户或团队)并按需配置认证。A2A Agent 可以按不同范围安装多次,因此 FlashAI 折叠卡片不会因为已有某个 FlashAI Agent 就自动消失。Agent 名称在账户内仍需唯一;如果同一个 FlashAI 域名需要安装多次,请在表单里调整名称。
不建议删除 FlashAI 模板生成的调用说明,尤其是开头的 `summary:` 简介——注册后 FlashAI 一定会出现在「可用 Agent 清单」里,但 AI SRE 是否把任务派给它,直接依据就是这行简介。说明过短或过于泛化时,AI SRE 可能继续在本地推理,或把普通 metrics / logs 问题错误委派给 FlashAI。
### 认证模式
A2A Agent 支持三种凭证供给方式,决定不同用户调用同一个远端 Agent 时如何提供凭证:
所有用户共用同一组凭证,凭证在「认证类型」中配置(Bearer Token 或 API Key)。适合团队共享同一个远端账号的场景。
每个用户在首次调用时单独提供自己的密钥,密钥加密存储在账户级别。需在「密钥 Schema」中配置 Header 名称(必填)、占位符与帮助链接(可选),供首次调用时引导用户填写。
用户通过 OAuth 2.1 流程各自授权;首次调用该 A2A Agent 时自动弹出授权窗口,完成后凭证按用户隔离保存。授权前需在凭证对话框选择**执行环境**:可选云端 Sandbox 或在线的 BYOC Runner,不能使用「自动」。OAuth 请求从所选环境发起;远端 OAuth 服务仅在内网可达时,请选择能够访问它的 BYOC Runner。
出于安全考虑,已保存的敏感字段(如 `token`、`api_key`、`client_secret`)在读取时会被**掩码**返回。编辑时若把敏感字段留空,表示「保留当前值」而非「清空」——只有当您显式修改它时才会覆盖已存储的凭证。
每用户 OAuth 的发现地址优先使用 HTTPS。只有在受控测试环境中,才为非本地 HTTP Card URL 勾选「允许通过 HTTP 进行 OAuth 发现」。如果 HTTPS 端点使用自签证书,也只应在可信网络内临时开启「跳过 TLS 证书校验」。
## 入站:让外部 Agent 调用 AI SRE
***
在 A2A Agents 页面顶部展开「**让外部 Agent 调用 Flashduty 的 AI SRE**」面板,即可获取本账户 AI SRE 的 **Agent Card** 地址:
```
https://api.flashcat.cloud/safari/a2a/ai-sre/agent-card
```
把该地址填入任意 A2A 客户端,即可经 A2A 协议调用 Flashduty 的 AI SRE Agent。
**鉴权**:在请求头加上 `Fd-App-Key: <你的 app_key>`(或使用 `?app_key=` 查询参数)。Agent Card 对外声明的能力包括:
| 能力(Skill) | 说明 |
| ---------------------- | ------------------------------------- |
| `investigate_incident` | 端到端地为一个 Flashduty 故障定位根因,关联日志、指标与近期变更 |
| `analyze_logs` | 在指定时间窗内查询并总结目标服务的日志 |
| `analyze_metrics` | 在指定时间窗内查询并总结目标服务的指标 |
Agent Card 同时声明了 Flashduty 的「运行选项」A2A 扩展:调用方可在 `message.metadata` 中按需覆盖 `incognito`(是否在会话列表中隐藏,默认隐藏)、`visibility`(`private` / `account`)、以及运行环境(`cloud` / `byoc` 与具体 `environment_id`)。该扩展为可选项,朴素的 A2A 客户端无需理会即可正常调用。
### 故障与作战室联动
当一个会话**经由故障路由进入**(例如从故障或作战室触发 AI SRE)时,平台会把对应的故障绑定到本次会话,并作为上下文带入,让排障从一开始就锚定在正确的故障上。基于此,AI SRE 可在对话中借助内置 Skill 进一步操作故障——读取故障详情、查询时间线、创建 / 查看作战室、关联变更等。IM 侧的作战室自动诊断详见 [IM 集成](/zh/ai-sre/im)。
A2A 与故障的**自动联动**目前在概念上受支持、并在持续演进中:故障自动绑定尚未完整可用,跨 Agent 的双向事件流会随版本逐步完善。请勿将其视为已完整可用的能力——公测期间以实际开通的功能为准。
## 创建与管理
***
A2A Agent 的完整生命周期可在 **插件 → Agents** 页面管理。
点击 **添加 A2A Agent**,填写名称、范围、调用说明、Card URL、认证等并保存。创建时需选定一个明确的作用域(账户或团队),未选定前提交按钮保持禁用。
用列表中的开关切换 A2A Agent 的启用状态。仅**已启用**的 Agent 会进入 AI SRE 的可用清单、可被委派任务;禁用后立即对委派不可见。
点击列表中的任意一行打开表单,可查看与编辑名称、调用说明、范围、Card URL、认证配置、流式与认证模式。无编辑权限时表单显示为**只读**。
从当前范围移除一个 A2A Agent。**委派给它的活跃会话将会失败。** 删除有确认提示。
列表顶部的范围筛选条可在「全部」「仅账户级」「指定团队」之间切换,便于在大量资源中聚焦查看。每行还会以标签标注其范围(账户 / 团队名)。筛选条右侧的搜索框支持按名称、调用说明或 Card URL 中的关键词过滤列表。
## 作用域
***
A2A Agent 与其他资源(Skill、知识库、MCP、运行环境)共用同一套**两级作用域**模型,分为账户级与团队级:
| 作用域 | 可见性 |
| --- | --------- |
| 账户级 | 账户内所有成员可见 |
| 团队级 | 仅该团队成员可见 |
**编辑权限**:账户所有者或账户管理员可编辑任意 Agent;团队成员可编辑**本团队**的团队级 Agent;没有「创建者保留权限」这一例外。无编辑权限时,列表对应行显示为**只读**。
**创建与改归属**:创建新的团队级 Agent 时,您必须是目标团队成员;账户级创建仅限账户所有者或管理员。编辑已有 Agent 时,账户所有者或管理员可以把它移动到任意团队,用于恢复空团队或离职成员留下的资源;普通成员只能移动到自己所属的团队。
**运行时可见性**:会话开始时,AI SRE 的可用 Agent 清单中只会呈现**账户级**资源,以及**当前会话所绑定团队**的资源(如故障 / 作战室带入的团队,或界面上显式选择的团队)。当 Agent 在排障中读取另一个团队的知识后,该团队的 Skill、MCP 与 A2A Agent 才会被按需挂载进当前会话。**账户是运行时唯一的安全边界,团队只是归属与编辑的标记。**
## 相关页面
***
在会话中观察 A2A 委派的任务卡片及其子会话面板。
为 Agent 接入外部工具,扩展其在任务中的能力边界。
用 DUTY.md 与知识包为 Agent 提供团队上下文与排障经验。
在 IM 群里 @ AI SRE,并了解故障作战室的自动诊断。
了解 AI SRE 的整体能力与定位。
# Apps
Source: https://docs.flashduty.com/zh/ai-sre/apps
Apps 用于管理 AI SRE 已授权的外部应用,包括 GitHub、GitLab 与 Kubernetes App。你可以授权代码仓库,或将 Kubernetes 集群以指定的 namespace 与权限边界接入 AI SRE。
**公测功能**:AI SRE 已全量开放公测,无需申请,登录控制台即可直接使用,公测期间免费。功能与界面可能继续调整。
## 概述
***
**Apps** 是管理「已授权的外部应用」的地方。每个外部应用以一张**应用卡片**呈现——你在它的卡片上完成授权、管理安装、并随时启停或撤销。
Apps 包含 **GitHub**、**GitLab** 和 **Kubernetes App**。GitHub 与 GitLab 用于授权代码仓库:AI SRE 可以在会话中读代码、调查变更 / 提交 / PR(GitLab 中为 MR),并按需修改缺陷、创建 PR / MR 或 issue。Kubernetes App 则把指定 Kubernetes 集群接入 AI SRE,并通过配置的 namespace 与权限边界限制 Agent 的操作范围。
## 主要场景:让云端沙箱访问你的仓库
***
AI SRE 的会话默认运行在 **Flashduty 云端沙箱**里。沙箱是干净、隔离的临时环境,**不带你的任何 git 登录凭证**——这正是 App 要解决的问题。授权 GitHub App 或 GitLab App 后,沙箱里的 Agent 才能 clone 你的仓库、读 diff、开 PR / MR,而**你无需向它交出任何密码或 token**;它的访问被限制在你授权的那些仓库,且仅为完成任务所需的最小权限。**这是这两个 App 的主要用途。**
**BYOC(自托管 Runner)一般用不到它。** Runner 跑在你自己的机器上,那台机器通常**已经配好了 `gh` / `glab` / `git` 凭证**(你平时就在上面操作仓库)。这种情况下 Agent 直接用宿主机自带的凭证即可,**不需要再授权对应的 App**。(若宿主机恰好没配相应凭证,授权 App 同样能让 BYOC 会话用上。)运行环境的差异见 [运行环境(BYOC)](/zh/ai-sre/environments)。
## 位置
***
进入 **插件 → Apps**。Apps 是插件区的**第一个、也是默认**标签页——打开插件区即落在这里。
查看 Apps 标签页需要相应权限;没有权限时该标签页不可见。授权、断开 / 撤销、启用 / 禁用各自还需对应的操作权限——无权限时对应按钮以禁用态显示。
## Kubernetes App
***
Kubernetes App 将集群中的 Agent 接入 AI SRE。创建后,AI SRE 可以在授权范围内查询集群信息并执行可用的 Kubernetes 工具;它只能访问你在配置中指定的 namespace 和权限级别。
### 创建并安装
进入 **插件 → Apps → Kubernetes App**,点击 **创建 Kubernetes App**。填写集群名称,并选择范围:**共享** 可供账户内所有会话使用;**团队** 可供该团队会话及该团队成员的个人会话使用。同一范围内的集群名称不能重复。
选择 **全部 namespace** 或 **指定 namespace**。全部 namespace 会把同一权限应用到当前和未来的 namespace;指定 namespace 可以为每个 namespace 单独选择 **只读** 或 **读取 + 有限修改**。不填写指定 namespace 时,Agent 只能读取集群基础元数据。
保存后复制控制台生成的安装命令,并在目标集群中执行。安装命令会过期;过期后重新打开安装配置或查看 Manifest 生成新命令,无需轮换 Token。
修改 namespace 或权限后,必须重新执行安装命令,集群中的 RBAC 才会更新。选择 **读取 + 有限修改** 前,请确认该 namespace 中允许 AI SRE 执行相应操作。
### 编辑与撤销
你可以在 Kubernetes App 列表中编辑集群名称、范围和 namespace 权限。将范围改为**共享**与创建共享 App 同门槛:仅限账户 Owner / 管理员操作,普通成员即使编辑自己团队的 App 也不能把它提升为共享,只能把 App 移动到其所属的团队。撤销会立即使连接和 Token 失效,但不会自动删除集群中的 Agent 与 RBAC。控制台会提供卸载命令;请在对应集群执行它。该命令只删除当前 Kubernetes App 的资源,不会删除共享的 `flashduty` namespace。
## GitHub 应用
***
下面先以 **GitHub** 为例,介绍授权、安装管理与仓库授权的调整;**GitLab** 的流程见下一节。
### 连接 GitHub 组织
在 GitHub 卡片上发起授权,整个安装在一个弹窗里、通过 GitHub 官方的安装页完成,回调后列表自动刷新。
在 GitHub 卡片上点击 **去授权**(如果该 App 已有安装,按钮显示为 **更多仓库**,带一个 + 号图标)。前端随即打开一个弹窗,加载 GitHub 官方的安装页。
选择要安装到的**组织**(或个人账户),并授予仓库范围——**所有仓库(All repositories)**或**仅选定仓库(Only select repositories)**。授予的仓库集合决定了 AI SRE 之后能访问哪些仓库。
你在 GitHub 上确认后,弹窗自动关闭,Apps 页提示 **授权成功** 并刷新安装列表,新组织随即出现。
若你不是该组织的所有者,GitHub 会把请求转交给组织所有者走「请求安装」的审批流程;审批通过后该安装才会激活。安装到哪个组织、授予哪些仓库,完全由 GitHub 侧的安装页决定,Flashduty 不在中间代为选择。
### 安装管理
每授权一个组织,就在 GitHub 卡片下多出一行安装记录。每行展示:
| 元素 | 说明 |
| --- | ------------------------------------ |
| 组织名 | 安装所在的 GitHub 组织 / 账户登录名 |
| 状态点 | 一个彩色小圆点 + 文案:**已连接**、**已暂停**、**已撤销** |
| 仓库数 | 该安装当前授予的仓库数量 |
卡片右上角的开关在「启用」与「禁用」之间切换。**禁用 = 暂停**:暂停后 Agent 无法再访问这些仓库,但 **GitHub 上的安装本身保留**,可随时一键重新启用、无需再走一遍 GitHub 授权。一个 App 只要还有至少一个**已连接**的安装,就视为「已启用」。
在某一行点击 **撤销**,确认后该安装置为 **已撤销**,AI SRE 从此不再能访问该组织的仓库。撤销后该安装从卡片上隐去,重新授权同一组织即可恢复。
**暂停**与**撤销**的区别:暂停是临时关掉、保留 GitHub 安装、可一键恢复;撤销是断开这次授权、需要重新走 GitHub 授权才能再用。
### 新增或调整仓库授权
某个组织已经连接好了,但你想让 AI SRE 访问该组织里更多的仓库——不必撤销重连。在 **插件 → Apps** 里,对该组织再次点击 **更多仓库**(或直接打开该 App 在 GitHub 上的 **Configure** 页),GitHub 会展示 **Repository access** 选择界面;勾选你要新增的仓库并保存,AI SRE 会**自动重新同步**已授予的仓库列表,新仓库无需重建连接就能用。
**兜底**:如果新加的仓库在会话里仍报「无法访问 / 404 / 403」,到 GitHub 上打开该 App 的页面(如 `github.com/apps/flashduty`)→ **Configure** → 选中对应组织 → 拉到底部的 **Danger zone** → **Uninstall** 卸载该安装。然后回到 Flashduty 的 **插件 → Apps** 重新授权该组织,并在这一次里一并勾选你需要的**全部**仓库。
## GitLab 应用
***
**GitLab** 应用连接一个 GitLab 实例——不管是 **GitLab.com**、**极狐 GitLab**(jihulab.com SaaS 或私有化发行版),还是你自己的其他**自建(Self-managed)**实例,连接方式都**完全一样**:先在该实例上注册一个 OAuth 应用,再完成授权。授权之后,AI SRE 就能在授权范围内的仓库里读代码、调查变更 / MR、并在你需要时提 issue、开 MR。和 GitHub 一样,**你不需要粘贴任何个人令牌**:Flashduty 通过 OAuth 拿到授权后,会为你的账户配置一个专属的机器人身份来完成实际访问。
### 连接 GitLab 实例
在 GitLab 卡片上点击 **Connect**,三选一:
* **GitLab.com**——地址固定为 `https://gitlab.com`,无需填写;
* **极狐 GitLab**——地址固定为 `https://jihulab.com`,无需填写;
* **自建实例 / Self-managed**——需要填写实例的根地址:浏览器地址栏里群组 / 项目路径**之前**的那部分,例如 `https://gitlab.example.com`;如果实例部署在子路径下,要带上子路径,例如 `https://example.com/gitlab`。
连接和重新授权 GitLab 时的网络请求会从这里选择的环境发出。GitLab.com、极狐 GitLab 等公网实例可使用默认云端环境;只有内网可访问的自建实例,请选择能够访问它的 BYOC Runner。系统不会在 Runner 离线或不可达时自动切换环境,请选择可用环境后重新发起连接或授权。
连接向导会展示一个**可复制的 Redirect URI**。带着它去你填写的 GitLab 实例创建一个 OAuth 应用:group **Owner** 在 **Group Settings → Applications** 创建一个归属分组的应用;在 **GitLab.com** 上,如果你不是任何分组的 Owner,也可以在 **User Settings → Applications** 创建一个归属你个人账户的应用;实例管理员也可以在 **Admin Area → Applications** 创建。填入向导给出的 Redirect URI,勾选 **Confidential**,Scopes 只勾 **api**。创建后 GitLab 会给出一个 **Application ID** 和一个 **Secret**,回到连接向导粘贴这两项。
这一步对**每一个** GitLab 实例都一样——GitLab.com、极狐 GitLab(jihulab.com SaaS 及其私有化发行版)、或任何其他自建实例:地址不同,注册 OAuth 应用、粘贴 Application ID / Secret 的步骤完全相同。
这一步会显示这次要用哪个实例的哪个 OAuth 应用来授权;如果想换一个应用,点击 **更换 OAuth 应用** 回到上一步重新注册。确认无误后,向导打开一个弹窗,跳转到 GitLab 的官方授权页;用你的 GitLab 账户登录并确认授权。授权完成后弹窗自动关闭,向导进入下一步。
AI SRE 展示一个仓库选择器,列出**你拥有 Owner 角色的分组**和**你拥有 Maintainer 角色的项目**。勾选想让 AI SRE 访问的分组 / 项目并保存——勾选一个分组即覆盖其下的所有项目,包括之后新建的项目。
一个账户同一时间只能连接**一个** GitLab 实例(GitLab.com 或某一个自建实例)。要换成另一个实例,需要先断开当前这个。
### 机器人身份与权限
保存仓库选择后,Flashduty 会在这些分组 / 项目下为账户配置一个专属机器人(优先使用服务账号;实例不支持服务账号时,回退为分组 / 项目级的访问令牌),供 AI SRE 会话使用。无论哪种方式,机器人的权限都被限制在 **Developer** 级别,和你在 GitLab 里能授予的最小权限一致。令牌会在到期前**自动轮换**,无需你手动处理。
如果这个 GitLab 实例不支持服务账号,机器人会回退为分组 / 项目级令牌——这类令牌本身只能绑定单个分组或项目,因此仓库选择器会限制为最多选择**一个**分组或一个项目。若你在多选状态下勾选了多个分组 / 项目并保存,Flashduty 会提示「该 GitLab 实例不支持服务账号,请仅选择一个分组或一个项目后重试」,并把选择器切换为**单选模式**:之后再勾选新的分组或项目会自动清空其余已选项,需要重新只保留一个分组或一个项目后再次保存。
**GitLab.com 上的一条限制**:GitLab 官方规定,分组 / 项目级访问令牌只在**付费(非免费、非试用)命名空间**上可用。连接 GitLab.com 本身不受影响,但如果你要授权的分组 / 项目所在命名空间是免费版或试用版,机器人配置会失败,界面上会展示一条来自 GitLab 的说明("provisioning\_denied")。把对应命名空间升级到付费版后重新授权即可。
### 管理已连接的实例
GitLab 卡片下会显示当前连接的实例地址与状态。
重新打开仓库选择器,勾选新增的分组 / 项目,或取消勾选不再需要的——保存后 AI SRE 的访问范围随即更新。
断开这次连接。Flashduty 会尽力清理为这个账户配置的机器人身份及其名下的令牌;如果某一步清理没有成功,界面会给出提示。断开后该实例的所有访问随即失效,重新连接需要再走一遍 OAuth 授权。
## AI SRE 如何在仓库里工作
***
授权之后你无需任何额外配置。当你在会话里让 AI SRE 处理某个仓库的任务时,它会像一名加入项目的工程师那样工作——先理解,再动手,最后验证。这套行为分别由内置的 `github` Skill 与 `gitlab` Skill 约束。
**典型动作**
* **进入仓库**:把仓库 clone 进自己的工作区,并优先阅读仓库自带的约定(`CLAUDE.md`、`AGENTS.md`、`README`、`CONTRIBUTING`)。
* **调查变更 / PR / MR**:用 `git log`,以及 GitHub 上的 `gh pr list` / `gh pr view` / `gh pr diff` / `gh search prs`,或 GitLab 上等效的 `glab mr list` / `glab mr view` / `glab mr diff`,追溯故障 / 变更工单里提到的 PR / MR、看某次发布包含了什么、在决策前读懂一段 diff。
* **改动并提交**:新建分支、用最小的 diff 改动,用 `gh pr create` 或 `glab mr create` 开一个可评审的 PR / MR,或用 `gh issue create` / `glab issue create` 提一个 issue,并把链接回报给你。
**硬性护栏**——这些规则 Agent 绝不逾越:
* **绝不强推**(`git push --force`),**绝不直接推默认分支**——一律走「分支 + PR / MR」。
* **一个 PR / MR 只装一处逻辑变更**,保持可评审;改动一旦膨胀超出聚焦的 diff,就停下把分析交回给你。
* 绝不删分支、关闭他人的 issue / PR / MR,或改动仓库设置;绝不提交密钥、凭证或构建产物。
如果在云会话里 Agent 报告无法访问仓库,通常是账户尚未授权对应的 App(GitHub 或 GitLab)、或没有把目标仓库 / 分组纳入授权范围——到 **插件 → Apps** 补充授权即可。Agent **不会**向你索要任何令牌。
## 权限与范围
***
GitHub App 与 GitLab App 的**授权**与**撤销 / 断开**都是**账户级**操作。**账户是唯一的安全边界**,团队在这里只是归属 / 审计标记:账户内任何具备相应权限的成员都可以完成授权、撤销 / 断开、或启停整个 App;会话在用到某仓库时,也从账户内当前有效的安装取得访问凭证。账户内的成员共享同一套授权——这与 AI SRE 其它资源「使用 = 账户级、归属 = 团队标记」的模型一致。
两者的范围模型略有差别:**GitHub App** 允许同一账户安装多个组织,各自独立启停 / 撤销;**GitLab App** 每个账户**同一时间只能连接一个** GitLab 实例——要切换到另一个实例,需要先断开当前这个。
## 相关页面
***
通过 Model Context Protocol 接入外部工具与数据源。
在会话中观察 Agent 如何 clone 仓库、读 diff、开 PR / MR。
BYOC 会话用 Runner 宿主机自带的凭证,一般不需要 GitHub / GitLab App。
内置的 github / gitlab Skill 约束 Agent 在仓库里的工作方式。
# 产物
Source: https://docs.flashduty.com/zh/ai-sre/artifacts
产物库集中呈现 AI SRE 会话中用 present_files 工具产出、再经 publish_artifact 工具发布的文件(网页、报告、图片、PDF、源码与数据文件等,例如 /insight 报告),支持搜索、按范围筛选与修改范围、重命名、分享(账户内或公开链接)、下载和删除。
**公测功能**:AI SRE 已全量开放公测,无需申请,登录控制台即可直接使用,公测期间免费。功能与界面可能继续调整。
## 概述
***
产物(Artifact)是 AI SRE 在会话中用 `present_files` 工具产出、再经 `publish_artifact` 工具发布到产物库的文件。最典型的是一份自包含的 HTML 报告或页面——例如在会话里输入 `/insight` 生成的运营洞察报告——但可发布的类型不止于此:
| 类别 | 常见扩展名 |
| ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 网页与文档 | `.html` `.htm` `.md` `.markdown` `.txt` `.log` |
| 数据与配置 | `.csv` `.tsv` `.json` `.yaml` `.yml` `.xml` `.toml` `.ini` |
| 图片 | `.png` `.jpg` `.jpeg` `.gif` `.svg` `.webp` |
| PDF | `.pdf` |
| 源码 | `.py` `.go` `.js` `.mjs` `.ts` `.jsx` `.tsx` `.java` `.c` `.h` `.cpp` `.cs` `.rb` `.rs` `.php` `.sh` `.sql` `.kt` `.swift` `.scala` `.css` `.vue` `.svelte` `.proto` `.tf` `.hcl` 等 |
| 压缩包 | `.zip` `.tar` `.gz` `.tgz` |
不在可发布范围内的文件,会话中不会出现「发布到产物库」按钮。
发布后的产物初始继承来源会话的作用域:来自个人会话的产物归创建者「个人」所有;来自绑定了团队的会话的产物归该「团队」所有,可分享给账户内的其它成员查看。拥有编辑权限时,之后还可以修改产物范围。
入口:左侧导航 **AI SRE → 产物**,对应路由 `/ai-sre/artifacts`。
产物库本身没有手动上传或创建文件的入口——产物都是 Agent 在会话中用工具产出并发布的;控制台只提供浏览、检索与管理已发布产物的能力。
## 列表页
***
### 搜索与范围筛选
* **搜索框**:按标题模糊搜索已发布产物,输入停顿 300 毫秒后自动查询。
* **范围**:**全部 / 个人 / 团队** 三态切换(与 Customize 下其它资源统一的两级作用域一致)。选择「团队」后会展开一个可搜索、可多选具体团队的选择器;不选择任何团队等价于「我可见的全部团队」。
### 产物卡片
每张卡片展示:
* 顶部预览区的类型图标:按文件扩展名与内容类型区分,图片、PDF、HTML、Markdown、表格(CSV / TSV)、JSON、压缩包、源码各有专属图标,无法识别时回退为通用文件图标;
* 标题(单行显示,超出省略;鼠标悬停可看到完整标题);
* 时间信息以 **「创建于 …」** 为主,创建时间与编辑时间不同时(产物在创建后又被更新过)才在旁边同时显示「编辑于 …」;两者都用相对时间表示——刚刚 / N 分钟前 / N 小时前 / N 天前,超过 30 天则显示具体日期;没有 `created_at` 的旧数据回退为只显示「编辑于 …」;
* 右下角的作用域徽标:团队产物显示团队名称(绿色高亮),个人产物显示创建者姓名(灰色)。
点击卡片正文会打开该产物的详情页;鼠标悬停在卡片上会在右上角露出「更多操作」按钮(触屏设备上始终可见)。
### 新建产物
点击页面右上角的 **新建产物**,会跳转到会话页面并预填一段引导草稿:
> 我想在 Flashduty AI-SRE 中创建一个可发布的产物:一个用 publish\_artifact 工具发布的自包含网页或报告。请先问我几个必要问题,包括目标读者、内容/数据、交互和视觉风格,然后构建并发布它。
Agent 会先向你确认目标读者、内容/数据来源、交互与视觉风格等细节,再动手构建并发布,而不是打开一个表单直接创建。
除此之外,任何一次会话中用 `present_files` 展示出来的文件旁边也带有一个「发布到产物库」按钮,可以把该次会话已经产出的文件直接发布为产物——这是比「新建产物」更直接的路径,不必再走一次完整对话。
## 卡片操作
***
每张卡片右上角的「更多操作」菜单提供:
| 操作 | 说明 |
| ---- | ----------------------------------------------------- |
| 复制链接 | 复制该产物详情页的完整 URL,可分享给账户内的其它成员打开 |
| 下载 | 仅当产物关联着文件(`file_id` 非空)时出现,下载原始文件 |
| 重命名 | 仅当你对该产物有编辑权限时出现;打开一个对话框修改标题 |
| 修改范围 | 仅当你对该产物有编辑权限时出现;选择个人或可访问的团队。只有产物创建者可以将范围改为个人 |
| 删除 | 仅当你对该产物有编辑权限时出现;删除前需二次确认,删除后产物从产物库移除,但来源会话与文件本身保留不受影响 |
## 详情页
***
详情页路由为 `/ai-sre/artifacts/:artifactId`,顶部工具栏提供:
* **标题**:对有编辑权限的产物可直接点击标题进行行内编辑(无需跳转到独立表单),按 Enter 保存、Esc 取消;
* **创建者**:标题下方显示「〈创建者〉创建的产物」;
* **分享**:打开分享面板,可选择「仅账户内」或「公开链接」两种可见范围,详见下文 [分享产物](#分享产物);
* **删除**:仅在你有编辑权限时显示,删除前需二次确认;
* **更多操作**:只有以下至少一项可用时才会出现这个菜单——
* **下载**:仅当产物关联着文件时出现。
* **修改范围**:仅当你有编辑权限时出现,可将产物移至可访问的团队;产物创建者还可以改回个人范围。
标题下方是一条 **来源会话信息条**:
* 展示产物自身的「创建于 …」「编辑于 …」时间(与列表卡片一致:创建与编辑时间不同时才同时显示);
* 当产物的来源会话你仍有权限访问时,信息条里会出现 **「最近更新来自会话 〈会话名〉」** 按钮——会话名由 `/safari/session/get` 解析来源会话得到,点击跳转到该会话的完整对话(`chat?session_id=<会话ID>`,消息、工具调用、产物历史)。来源会话已删除或无权访问时,该按钮隐藏,产物本身仍可正常查看。
正文区域按产物的实际内容类型渲染(例如 HTML 报告会直接内联展示为页面)。
## 分享产物
***
详情页工具栏的 **分享** 按钮会打开分享面板。面板顶部的 **管理权限** 列出谁可以管理这个产物的分享(创建者标记为「所有者」,团队产物还会列出团队成员);下方的 **可见权限** 提供两种模式:
| 模式 | 谁能打开 | 内容 |
| ---- | ----------------- | -------------------------------- |
| 仅账户内 | 登录同一账户的成员 | 账号内成员登录后可查看,内容**始终为最新版本** |
| 公开链接 | 任何拿到链接的人,**无需登录** | 展示的是生成链接那一刻的**内容快照**,产物更新后不会自动同步 |
### 公开链接
**版本要求**:公开链接需要 On-call 专业版及以上订阅,随 AI SRE 公测一并开放。[了解更多](https://flashcat.cloud/flashduty/price/)
选择 **公开链接** 后,面板会先展示一段内容预览和风险提示,再由你点击 **生成公开链接** 才真正生效:
生成公开链接后,任何拿到链接的人都可以查看此产物,链接也可能被继续转发。请勿分享密钥、个人信息或未经授权的第三方内容。
生成成功后链接会自动复制到剪贴板(提示「公开链接已生成,已复制到剪贴板」)。公开链接的形式为 `https://<控制台域名>/share/artifact/<产物 ID>`——它以产物自身的 ID 为标识,不携带令牌;匿名访问完全由 CDN 提供,不经过任何需要登录的接口。
打开公开链接的访问者会看到只读的内容页:页面顶部在标题旁标注「**内容由用户生成,未经核实。**」声明,并提供「**反馈**」入口——点击跳转到举报表单(已自动预填当前链接),任何人都可以向 Flashduty 举报不当内容;页面同时提供「登录」入口,引导访问者登录控制台。
| 操作 | 说明 |
| ------ | -------------------------------------------------------------------- |
| 生成公开链接 | 把产物当前内容复制为一份公开快照并启用链接 |
| 更新快照 | 仅当检测到产物内容已更新时出现(提示「识别到产物内容有更新,可更新快照以同步最新内容」)。点击后用最新内容覆盖快照,**链接保持不变** |
| 撤销公开链接 | 关闭公开访问,链接立即失效 |
超过 **16 MiB** 的产物无法生成公开链接,会提示该产物体积超限。此时仍可使用「仅账户内」模式分享。
## 权限
***
产物是否可编辑(重命名、修改范围、删除)由后端返回的 `can_edit` 字段决定,满足以下任一条件即可管理该产物:
| 条件 | 说明 |
| -------------- | ---------------------------------------- |
| 创建者本人 | 发布该产物所属会话的所有者 |
| 账户 Owner / 管理员 | 对账户内任意产物(无论个人还是团队作用域)都有管理权限 |
| 团队成员(仅团队产物) | 当产物属于某个团队(`team_id > 0`)时,该团队的其它成员也可以管理它 |
没有编辑权限的产物,卡片与详情页只提供「复制链接」「下载」等只读操作,「重命名」「删除」按钮不会出现。
这与自动化规则的权限模型不同:账户 Owner / 管理员对**任意**产物(含他人的个人产物)都有管理权限,不存在『个人资源管理员无豁免』的限制。
## 相关页面
***
了解会话如何用 present\_files 工具展示文件——产物正是从这些文件发布而来。
`/insight` 生成的运营洞察报告本身就是一种产物,可以在产物库里统一管理。
定时自动化跑出的运行也可以把产出的报告发布为产物,长期沉淀在产物库里。
# 自动化
Source: https://docs.flashduty.com/zh/ai-sre/automations
让 AI SRE 按 cron 周期、HTTP API 或 On-call 故障事件自动运行一个隐藏会话,用一段任务提示词产出巡检、洞察或复盘结果;本文介绍自动化规则的新建、配置字段、触发方式、运行历史与权限。
**公测功能**:AI SRE 已全量开放公测,无需申请,登录控制台即可直接使用,公测期间免费。功能与界面可能继续调整。
## 概述
***
自动化(Automation)让 AI SRE 按你设定的节奏自行跑一次 **隐藏会话**——它不出现在控制台左侧的会话列表里,而是在后台用一段固定的 **任务提示词** 驱动 Agent 完成工作,产出巡检、运营洞察或故障复盘等结果。
每条自动化是一条 **规则(rule)**。一条规则至少携带一种触发方式:
* **按周期执行**:用 4 段或 5 段 cron 设定运行节奏(例如每周一上午、每天 09:15),到点自动跑。
* **经 API 调用**:生成一个带 Bearer Token 的触发地址,你在外部系统里用 `POST` 按需触发,把本次运行的上下文随请求体一起带进来。
* **On-call 故障触发**:选择要监听的 On-call 协作空间与严重程度,当匹配故障产生时自动拉起一次诊断运行。
什么时候用它:把重复的例行巡检(如每日健康巡检)、定期产出的洞察 / 复盘报告交给 AI SRE 自动跑;或者把 AI SRE 接进你已有的流水线、变更系统或 On-call 故障流,在事件发生时拉起一次诊断。
入口:左侧导航 **AI SRE → 自动化**,对应路由 `/ai-sre/automations`。
自动化跑出的每一次运行,本质上仍是一个 AI SRE 会话——只是它被标记为隐藏,不混进你的日常会话列表。你随时可以从运行历史点进去,看到这次运行完整的对话、工具调用与产物。
## 新建自动化
***
页面右上角提供两个创建入口:outline 样式的 **通过聊天创建** 按钮,点击后跳转到会话页面并带一段预填的引导提示——「我们来创建一个自动化任务。先说明自动化任务如何运作。然后通过提问了解我需要安排什么任务,以及它应在何时运行。」——由 Agent 通过对话帮你确定任务内容和触发方式,跳过表单;以及 primary 样式的 **创建** 按钮,点击后会弹出一个起始选择面板,提供两条入口:
选择 **从零开始**,进入空白表单,手动填写名称、任务提示词与触发方式。适合你已经清楚要让 Agent 做什么、想完全自定义提示词的场景。
下方列出一组 **预设模板** 卡片(由后端按界面语言下发,中文环境取 `zh-CN`、英文环境取 `en-US`),常见的有 **告警噪音分析**、**事故响应复盘**、**每周值班洞察**、**升级和值班负载分析** 等。点击任一模板卡片,会用模板预置的名称与任务提示词预填表单,你在此基础上微调即可。
无论从哪条入口进入,接下来都是同一张配置表单。
## 配置字段
***
配置表单的字段如下:
| 字段 | 必填 | 说明 |
| -------------- | -- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 名称 | 是 | 规则名称,最长 255 字符。占位示例:`每周值班洞察`。 |
| 范围 | 是 | 通过 **范围选择器** 选 **个人**(`team_id=0`)或某个 **团队**(`team_id>0`)。范围既决定这条规则的归属与编辑权限,也限定 **执行 Environment** 里可选的自托管 Runner——只有账户全局的 Runner,以及与该范围同团队的 Runner 才可选。 |
| 执行 Environment | 否 | 通过 **环境选择器** 选运行环境:**自动**(由后端挑选最优可用环境,默认值)、**云端沙箱**,或某个 **自托管(BYOC)Runner**。选了某个团队范围后,不属于该范围的团队 Runner 会被自动清除。 |
| 任务提示词 | 是 | 描述要让 AI SRE 执行的任务,用富文本编辑器撰写。这段提示词就是每次运行时发给 Agent 的内容。占位提示:`描述 Flashduty AI SRE 要执行的任务。` |
**执行 Environment** 的「自动」会在每次运行时由后端挑选当前最优的可用环境;「云端沙箱」是平台托管的临时沙箱;自托管 Runner 则把运行落在你自己的机器上。三者的差异与连接方式见 运行环境 。
## 触发方式
***
一条规则必须 **至少配置一种触发方式**。当前控制台表单在「触发方式」区提供 **按周期执行**、**经 API 调用** 与 **On-call 故障触发** 三种入口,三者可同时启用。
### 按周期执行(cron)
按时间周期自动运行。运行节奏支持两种 cron 写法:
* **4 段**:`小时 日期 月份 星期`,系统自动补 `minute=0`,适合整点任务。
* **5 段**:`分钟 小时 日期 月份 星期`,适合分钟级任务,例如 `15 9 * * *` 表示每天 09:15。
秒级 6 段不支持。分钟必须是一个固定整数;其它字段只支持下表中的简单写法:
| 段 | 取值范围 |
| --------- | ----------------------------------- |
| 分钟(仅 5 段) | `0`–`59` 的固定整数 |
| 小时 | `*`、`*/n`(n 为 1–23)或 `0`–`23` 的固定整数 |
| 日期 | `*` 或 `1`–`31` |
| 月份 | `*` 或 `1`–`12` |
| 星期 | `*` 或 `0`–`7`(`0` 与 `7` 均表示周日) |
为免手写表达式,界面提供四种模式:
| 模式 | 含义 |
| --- | --------------------- |
| 每小时 | 每小时运行一次;默认整点,也可指定分钟 |
| 每天 | 选一个时刻,每天该时刻运行 |
| 每周 | 选星期几 + 时刻,每周该时刻运行 |
| 自定义 | 直接填 4 段或 5 段 cron 表达式 |
**时区**:在 **每天 / 每周** 模式下,你选的时刻按 **本地时区** 理解,保存时会换算成 UTC,界面会在节奏摘要旁标注你的本地时区;**自定义** 模式下表达式按 **UTC** 解释,界面标注为 `UTC`。
实际执行时间可能与设定时间存在 **分钟级延迟**,这是有意为之,用于把系统负载分散开。请不要把规则当作秒级精确的定时器使用。
### 经 API 调用(HTTP POST)
让你在外部系统里按需触发这条自动化,而不依赖时间周期。
在「触发方式」中添加 **Call via API** 并保存规则。保存成功后,系统会一次性生成本次触发用的 **Token** 与 **触发地址**,并弹出一个包含 `curl` 示例的窗口。
Token **只显示一次**:请立即复制保存。关闭弹窗后无法再次查看,只能重新生成(轮换)一个新 Token——重新生成会使旧 Token 失效。
用 `POST` 调用触发地址,把 Token 放在 `Authorization: Bearer` 请求头里,请求体用 `text` 字段传入本次运行的上下文。弹窗里给出的 `curl` 示例形如:
```bash theme={null}
curl -X POST 'https://<触发地址>' \
-H 'Authorization: Bearer ' \
-H 'Content-Type: application/json' \
-d '{"text":"描述本次运行的事件或上下文。"}'
```
请求体里的 `text` 会作为本次运行的上下文交给 Agent,叠加在规则配置好的任务提示词之上。
请求成功后,响应的 `data` 会返回新建隐藏会话的信息。你可以保存 `session_id`,或直接使用 `session_url` 打开这次运行的完整对话、工具调用和产物:
```json theme={null}
{
"data": {
"type": "routine_fire",
"session_id": "",
"session_url": "https:///ai-sre/chat?session_id="
}
}
```
一条规则可以 **同时** 启用「按周期执行」与「经 API 调用」:到点自动跑,也允许外部按需拉起。每种触发方式各占一行,可分别 **移除**。
### On-call 故障触发
当你希望 AI SRE 随 On-call 故障自动启动时,添加 **On-call incident** 触发方式。触发器会向 On-call 侧注册订阅,只有匹配指定协作空间和严重程度的故障事件才会启动运行。
在「触发方式」中点击 **On-call incident** 卡片,表单会展开协作空间与严重程度条件。
在 **协作空间** 下拉框中选择要监听的 On-call 协作空间。个人范围规则可选择账户下可见的协作空间;团队范围规则会按所选团队收窄可选协作空间。
在 **严重程度** 中选择 `Critical`、`Warning`、`Info` 中的一个或多个值。启用该触发器时,协作空间和严重程度都至少需要一个值。
如果通过 API 创建或更新规则,对应字段如下:
| 字段 | 类型 | 说明 |
| --------------------------------- | --------- | ----------------------------------------------------------- |
| `oncall_incident_trigger_enabled` | boolean | 是否启用 On-call 故障触发器。 |
| `oncall_incident_channel_ids` | int64\[] | 监听的 On-call 协作空间 ID 列表;创建或启用该触发器时至少需要一个有效 ID。 |
| `oncall_incident_severities` | string\[] | 监听的故障严重程度,支持 `Critical`、`Warning`、`Info`;创建或启用该触发器时至少需要一个值。 |
匹配事件到达后,系统会以 `oncall_incident` 作为 `trigger_kind` 创建运行,并把 `incident_id`、`channel_id`、`severity` 等事件上下文传给会话。相同触发器与相同 `incident_id` 会复用同一次运行,避免同一故障重复拉起多个隐藏会话。
## 运行历史
***
每条规则都保留它的运行历史。点击规则行的任意位置(而不是某个专门的历史图标)会打开该规则的详情页 `/ai-sre/automations/:ruleId`:左侧栏是「配置信息」,右侧栏是「执行历史」,两栏并排展示;右侧栏顶部自带一个 **手动执行** 按钮,可以直接在详情页里触发一次运行。
运行历史以表格呈现,列为:
| 列 | 说明 |
| ---- | ---------------------------------------------------------------------------------------------- |
| 名称 | 本次运行对应的隐藏会话名称。后端会为每条运行批量解析其隐藏会话的标题(`session_name`,即该隐藏会话自动生成的会话名);解析不到时回退显示会话 ID(`session_id`) |
| 执行时间 | 本次运行的开始时间 |
| 耗时 | 本次运行的持续时长 |
| 触发方式 | 本次运行的触发类型标签,如 `定时`(schedule)、`HTTP POST`、`On-call incident` 或 `手动执行` |
| 状态 | 本次运行的状态(见下表) |
运行状态的取值:
| 状态 | 含义 |
| ----------- | ---------------- |
| `running` | 运行中 |
| `retrying` | 重试中 |
| `succeeded` | 成功 |
| `partial` | 部分成功 |
| `failed` | 失败 |
| `skipped` | 已跳过 |
| `abandoned` | 已放弃(长时间未完成被系统终止) |
表格上方提供三个筛选项:
* **时间范围**:默认显示 **最近 30 天**,可调整范围,最大跨度 **180 天**。
* **状态**:按上表中的运行状态过滤,或选 **全部状态**。
* **触发类型**:`全部触发类型` / `手动执行` / `定时` / `HTTP POST` / `On-call incident` 五选一。
API 返回的运行记录还包含 `trigger_kind`,可能取值为 `schedule`、`manual`、`http_post`、`oncall_incident` 或 `debug`。其中 `manual` 表示通过立即执行接口启动,`oncall_incident` 表示由匹配的 On-call 故障事件启动。
点击任意一行,会跳转到这次运行对应的隐藏会话对话页(`chat?session_id=<会话ID>`),让你查看该次运行完整的消息、工具调用与产物。
运行历史内嵌在规则详情页中,而打开详情页本身就要求你对该规则有编辑权限——没有编辑权限的规则连详情页都无法打开(会提示「自动化规则不存在或无权访问」),因此其运行历史也无法查看。
## 管理与权限
***
### 启用 / 停用、编辑与删除
每条规则在 **操作** 列提供一组操作:
| 操作 | 说明 |
| ------- | ----------------------------------------------------------- |
| 启用 / 停用 | 行内开关。停用后规则保留,但不再触发;停用不会删除已有运行历史。 |
| 立即执行 | 在规则行手动启动一次真实运行。该操作会先做运行前检查,然后为本次运行创建一个隐藏会话;同一规则手动执行最多每分钟一次。 |
点击规则行任意位置会打开该规则的详情页,在详情页里可以编辑配置、删除规则,也能看到运行历史(见上文「运行历史」一节)。
对你 **没有编辑权限** 的只读规则(`can_edit=false`),开关与全部操作按钮都会被禁用;打开其表单时顶部会显示「只读 — 你可以查看此自动化,但无法编辑。」
列表上方还提供两个筛选器:**范围**(全部 / 个人 / 团队,选「团队」后可多选具体团队)与 **状态**(全部状态 / 已启用 / 未启用)。
### 作用域与权限
自动化规则与 Customize 下的其它资源(Skill、知识库、MCP、Agent、运行环境)共用同一套两级作用域:
| 维度 | 规则 |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 归属 | **个人规则**(`team_id=0`)归创建者所有;**团队规则**(`team_id>0`)归该团队。创建团队规则时,规则 Owner 必须是目标团队的真实成员;账户 Owner 和管理员也没有豁免。你可以修改规则范围:个人规则可以转为团队规则、团队规则可以转属其它团队——这类变更要求规则 Owner 属于目标团队;但**团队规则不能转为个人**:编辑团队规则时,范围选择器不再提供「个人」选项(后端同样拒绝该转换),规则永远归属其团队。如需一份个人副本,请使用规则详情页的**克隆**按钮,在预填的创建表单中选择个人范围保存。每次运行前,系统还会再次校验团队规则的 Owner 仍属于该团队。 |
| 可见 / 列表 | 账户 Owner 与管理员可见全部规则;普通成员可见自己创建的规则,以及自己所属团队的规则。 |
| 编辑 / 管理(团队规则) | 账户 Owner 与管理员可管理任意团队规则;团队普通成员可管理自己所属团队的规则(启用 / 停用、编辑、删除)。 |
| 编辑 / 管理(个人规则) | 仅创建者本人可管理。账户 Owner 与管理员对他人的个人规则 **没有** 管理豁免,甚至无法查看其详情页——打开会直接返回「无权访问」,不是单纯的按钮置灰。 |
| HTTP POST 触发 | 通过触发地址发起一次真实运行时,鉴权只看该 trigger 的 Bearer Token;持有 Token 的外部系统可以触发,运行会按规则的个人或团队作用域创建隐藏会话。 |
| On-call 故障触发 | 由已注册的故障订阅触发,不使用 HTTP POST Bearer Token;运行仍按规则的个人或团队作用域创建隐藏会话。 |
账户 Owner / 管理员能在列表中看到其他成员的个人规则(见上表「可见 / 列表」),但点击进入详情页会被拒绝——「编辑 / 管理」权限不会像团队规则那样因 Owner / 管理员身份而对个人规则豁免。
账户是运行时唯一的安全边界,团队是「归属 / 编辑」标签。自动化规则的可见与管理沿用这套模型;与其它 Customize 资源一致的完整规则,详见各资源页面的「作用域」一节。
## 相关页面
***
了解会话如何承载一次完整对话——自动化跑出的每次运行本质上就是一个隐藏会话。
了解自动、云端沙箱与自托管 Runner 的差异,以及自动化的执行环境选择。
基于会话数据生成团队的故障处理与运营洞察,可作为定时自动化的产出目标。
为自动化运行提供领域知识,按团队范围加载。
自动化运行产出的报告如果被发布,会作为产物沉淀在产物库里,可长期查看与分享。
# 运行环境
Source: https://docs.flashduty.com/zh/ai-sre/environments
运行环境决定 AI SRE Agent 在哪里执行命令、读写文件、运行 Skill 与连接 MCP。本文先说明 Sandbox 与 BYOC Runner 的关系,再分别介绍云端 Sandbox、自托管 Runner、权限配置、会话选择与常见排查。
**公测功能**:AI SRE 已全量开放公测,无需申请,登录控制台即可直接使用,公测期间免费。功能与界面可能继续调整。
## 概述
***
**运行环境**(Environment)是 AI SRE Agent 实际执行动作的地方。Agent 的每一次工具调用,包括执行命令、读写文件、运行 Skill、连接 MCP 服务,都会落在一个运行环境里。
AI SRE 提供两类运行环境:
Flashduty 托管的临时容器,零安装、开箱即用。没有当前成员可用的在线 BYOC Runner 时,会话会自动回退到云端 Sandbox。
部署在您自己机器上的常驻进程。它通过 WebSocket 连接 AI SRE,让 Agent 在您的网络边界内执行任务。
默认选择逻辑是:**优先使用当前成员可用的在线 BYOC Runner;否则使用云端 Sandbox。** 可用 Runner 包括账户级 Runner,以及当前成员所属团队下的团队级 Runner。您也可以在会话输入框的环境选择器中固定使用云端 Sandbox,或固定使用某个具体 Runner。
控制台里的记录称为 **Environment**,跑在机器上的进程称为 **Runner**。一个 BYOC Environment 对应一个 Runner 进程;云端 Sandbox 则由系统按会话管理。
## 云端 Sandbox
***
云端 Sandbox 是 Flashduty 托管的临时执行容器。它适合快速上手、演示,以及不需要访问您内网的排查。您不需要安装任何进程,也不需要维护机器。
适合使用云端 Sandbox 的场景:
* 还没有部署 Runner,想先体验 AI SRE;
* 排查只需要访问 Flashduty 数据、可信公网服务或公开文档;
* 一次性、轻量任务,不值得准备常驻机器;
* 希望强制隔离在托管环境中执行,而不是使用账户下已有 Runner。
云端 Sandbox 不能访问您的 VPC、专线、内网数据库、内网 API 或跳板机。需要直连这些资源时,请使用 [BYOC Runner](#byoc-runner),把执行位置放到能访问目标资源的机器上。
更多生命周期、出网边界与会话选择细节,见 [Sandbox](/zh/ai-sre/sandbox)。
## 云端环境模板
***
云端环境模板是为 Flashduty 托管的云端 Sandbox 预定义的可复用配置:出口网络策略、环境变量与启动脚本。会话使用的云端 Sandbox 如果没有绑定模板,就用系统默认配置启动;绑定了模板后,新建的 Sandbox 会按模板配置启动。
在 AI SRE 左侧菜单进入 **Environments**,切换到顶部的**云端**标签页,即可查看、创建、编辑或删除云端环境模板。
### 创建云端环境模板
| 字段 | 是否必填 | 说明 |
| ---- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 名称 | 是 | 在账户范围内必须唯一,最长 128 字符。 |
| 范围 | 是 | 账户范围的模板在整个账户内可见;团队范围的模板仅对该团队成员可见和可编辑。 |
| 网络访问 | 否,默认「全部允许」 | 下拉框展示「默认允许列表」「自定义(你的域名列表)」「全部允许」三个选项,但目前只有\*\*「全部允许」\*\*可以选择——「默认允许列表」与「自定义」选项已在界面上展示但处于禁用状态,属于已知限制,尚未开放。也就是说,当前创建或编辑云端环境模板,都会让绑定它的 Sandbox 处于完全放开出网的状态。 |
| 环境变量 | 否 | `.env` 格式(`KEY=value`,每行一条,支持带引号的多行值),最大 32 KB,界面会实时显示已用字节数。 |
| 启动脚本 | 否 | Bash 脚本,最大 64 KB,界面会实时显示已用字节数。 |
环境变量以明文形式对所有使用该云端环境模板的人可见——请勿在这里填写密钥或凭据。
启动脚本在\*\*全新沙箱(Ubuntu 24.04,以 root 身份运行)\*\*内、**Agent 启动前**执行,典型用途是用 `apt` 安装 Agent 需要的软件包。
### 删除云端环境模板
删除一个云端环境模板不影响正在使用它的会话——已绑定的会话会回退为系统默认配置继续可用;后续新建的 Sandbox 会改用系统默认配置。
云端环境模板只配置**云端 Sandbox**的出网、环境变量与启动脚本。BYOC Runner 的出网策略由您自己的机器和防火墙决定,见下方 [BYOC Runner](#byoc-runner);云端 Sandbox 本身的生命周期与出网边界详见 [Sandbox](/zh/ai-sre/sandbox)。
## BYOC Runner
***
BYOC(Bring Your Own Compute)Runner 是您部署在自己机器上的 `flashduty-runner` 进程。它与 AI SRE 保持常驻 WebSocket 连接,收到任务后在本机执行命令、读写文件、运行 Skill,并按需连接本机可达的 MCP 服务。
BYOC Runner 的价值来自执行位置:
Runner 跑在您的机器上,因此能访问这台机器本身可达的 VPC、内网、专线、Kubernetes 集群、云厂商 CLI、数据库或跳板机。
命令输出、日志、临时文件和工具执行结果优先留在您的网络边界内。Agent 能读取和分析这些信息,但执行面仍由您机器的系统账号、文件权限和网络策略约束。
您可以决定 Runner 运行在哪个 OS 用户下、能访问哪些目录、拥有哪些 CLI 凭据,以及是否加载本页的[权限配置](#权限配置)收敛命令范围。
BYOC Runner 的出网策略由您的机器和防火墙决定。云端 Sandbox 的“按域名配置出网允许列表”不适用于 BYOC,因此自托管 Environment 表单里不提供网络访问配置。
### 创建并连接
在 AI SRE 左侧菜单进入 **Environments**,创建一个自托管 Environment。创建时需要填写:
| 字段 | 是否必填 | 说明 |
| -- | ---- | -------------------------------------------------------------------------------------------------- |
| 名称 | 否 | 在账户范围内唯一,最长 128 字符。留空时,Runner 首次连接并发送心跳后,会自动用机器主机名命名;若主机名重复,会追加 Environment ID 后缀。 |
| 范围 | 是 | 账户范围对整个账户可见;团队范围仅对该团队成员可见和可编辑。范围在创建时固定,之后不能修改;如需迁移,请在目标范围新建 Environment 并重新部署 Runner。见[作用域](#作用域)。 |
| 标签 | 否 | 用于任务路由的标签,逗号分隔,例如 `linux, docker, gpu`。 |
创建成功后会弹出**接入指引**,包含这条 Environment 的 Token、安装命令、升级命令和卸载命令。列表行里的钥匙按钮或 pending 状态的“查看接入指引”也会打开同一个弹窗。
### 安装方式
接入指引里的命令会自动填入真实 `TOKEN` 与 `URL`。以下示例只展示占位符,请以控制台生成的命令为准。
在目标机器上以 root / sudo 执行:
```bash theme={null}
curl -fsSL https://static.flashcat.cloud/flashduty-runner/install.sh | \
sudo TOKEN= \
URL= \
bash
```
脚本会安装二进制、创建 systemd 服务,并写入 `/etc/flashduty-runner/env`。同一条命令可用于首次安装和升级;如果已是最新版本,会自动跳过。
在已安装 Docker 的机器上启动容器:
```bash theme={null}
docker run -d \
--name flashduty-runner \
-e FLASHDUTY_RUNNER_TOKEN= \
-e FLASHDUTY_RUNNER_URL= \
-v /var/flashduty/workspace:/workspace \
registry.flashcat.cloud/public/flashduty-runner:latest
```
Docker 权限取决于容器挂载。需要 kubeconfig、云厂商 CLI 凭据或 Docker socket 时,在镜像名前追加对应的 `-v` / `-e` 参数。
先安装二进制,再手动启动进程:
```bash theme={null}
curl -fsSL https://static.flashcat.cloud/flashduty-runner/install.sh | sudo bash -s -- --no-service
FLASHDUTY_RUNNER_TOKEN= \
FLASHDUTY_RUNNER_URL= \
flashduty-runner run
```
手动模式不会注册 systemd 服务,适合 macOS、临时排查或您已有自己的进程管理方式。
`connect-url` 与 `install_script_url` 都由后端下发,前端不会硬编码。私有化或离线部署可以把安装脚本分发源替换为内部镜像,但镜像需要同时提供 `install.sh`、`releases/latest` 与 `releases/download//...` release assets。
### 连接使用自签证书的私有化端点
Runner 默认会校验控制 WebSocket 的证书链和主机名。私有化端点使用自签证书时,优先把对应 CA 加入 Runner 所在系统或容器的信任库;只有无法安装 CA、且端点位于可信私有网络内时,才关闭校验。
| 配置方式 | 值 | 默认值 | 说明 |
| ----- | ------------------------------------------------ | ------- | --------------------------- |
| 环境变量 | `FLASHDUTY_RUNNER_INSECURE_SKIP_TLS_VERIFY=true` | `false` | 适用于 systemd、Docker 和其他进程管理器 |
| 命令行参数 | `--insecure-skip-tls-verify` | 未启用 | 适用于手动运行;命令行参数优先于环境变量 |
编辑 `/etc/flashduty-runner/env`,写入私有化端点和 TLS 配置:
```bash theme={null}
FLASHDUTY_RUNNER_URL=wss://private.example.com/safari/environment/ws
FLASHDUTY_RUNNER_INSECURE_SKIP_TLS_VERIFY=true
```
重启 Runner,让新的环境变量生效:
```bash theme={null}
sudo systemctl restart flashduty-runner
```
创建容器时传入环境变量:
```bash theme={null}
docker run -d \
--name flashduty-runner \
-e FLASHDUTY_RUNNER_TOKEN= \
-e FLASHDUTY_RUNNER_URL=wss://private.example.com/safari/environment/ws \
-e FLASHDUTY_RUNNER_INSECURE_SKIP_TLS_VERIFY=true \
-v /var/flashduty/workspace:/workspace \
registry.flashcat.cloud/public/flashduty-runner:latest
```
启动时传入命令行参数:
```bash theme={null}
flashduty-runner run \
--token \
--url wss://private.example.com/safari/environment/ws \
--insecure-skip-tls-verify
```
如果环境变量已经设为 `true`,可以传入 `--insecure-skip-tls-verify=false`,显式恢复证书校验。
开启后,Runner 不再校验控制 WebSocket 的证书链和主机名,攻击者可能冒充控制端。该开关只影响 Runner 到 AI SRE 的控制 WebSocket,不会改变任务执行期间 MCP、A2A 或其他 HTTPS 请求的 TLS 配置。Runner 启动时会在日志中明确提示校验已关闭。
### Linux 服务用户
Linux (systemd) 安装默认使用安装脚本自动创建的 `flashduty` 用户。该用户没有 sudo 权限,systemd unit 会启用 `NoNewPrivileges=true`、`ProtectSystem=strict`、`PrivateTmp=true` 等限制,并只把 Runner 的状态目录设为可写。
如果 Runner 需要读取某个已有用户的 kubeconfig、云厂商 CLI 凭据或 Docker 权限组,可以在接入指引里填写“Linux 服务用户”,或手动在命令中增加 `RUN_AS`:
```bash theme={null}
curl -fsSL https://static.flashcat.cloud/flashduty-runner/install.sh | \
sudo TOKEN= \
URL= \
RUN_AS= \
bash
```
`RUN_AS` 等价于安装脚本的 `--run-as ` 参数,要求该系统用户已经存在。这样做会让 systemd 服务以该用户运行,也会相应放宽该用户主目录的保护策略。
只有在 Runner 确实需要读取该用户的本地凭据或加入该用户所在权限组时,才指定 `RUN_AS`。否则优先使用默认 `flashduty` 用户。
### Token、升级和卸载
Token 是 Runner 连接 AI SRE 的唯一凭据。它会写入安装命令或环境变量中,请只在安装、升级或排查连接时查看,不要发给无关人员。若怀疑泄露,请删除对应 Environment 后重新创建。
Runner 启动后会持续发送心跳。列表状态含义如下:
| 状态 | 含义 |
| -------------- | -------------------------------------------------------------- |
| 等待中(pending) | Environment 已创建,但 Runner 从未连接过。 |
| 在线(online) | Runner 当前已连接,心跳正常,可承接任务。 |
| 性能下降(degraded) | Runner 仍然连接着、心跳也正常,但它的执行器跟不上——任务排队积压或迟迟不返回。**可以继续使用,只是响应会变慢**。 |
| 离线(offline) | Runner 曾连接过,但当前心跳已断。 |
`degraded` 是一个**实时计算**的状态,不会被持久化:每次读取时根据当前信号重新判定,因此不需要手动清除。它由两类信号触发——
* 较新版本的 Runner 会在心跳里上报自身执行器的健康探针与积压任务数,据此直接判定;
* 不上报这些指标的旧版本 Runner,则采用回退规则:针对同一个 Environment **连续 3 次**任务超时即标记为性能下降(只有超过 20 秒的超时才计数,避免调用方自己设置的短超时被误判)。
恢复同样是自动的:新版本 Runner 的心跳恢复正常(探针通过且无积压)即回到 `在线`;旧版本 Runner 只要有任意一次任务成功就会重置计数,或在持续安静 30 分钟后自动恢复。
看到 `性能下降` 时,先检查 Runner 所在主机的 CPU、内存与磁盘负载,以及是否有长时间占用执行器的任务。它不阻断会话,但持续处于该状态说明这台主机已经吃不消当前的任务量。
Runner 版本由服务端在心跳中比对。发现新版本时,Runner 会收到升级通知并自行下载、校验、替换。手动重跑安装命令也可升级。
卸载命令也在接入指引里,按安装方式不同:
* **Linux (systemd) / 手动安装**:安装脚本的 `--uninstall`(保留配置卸载)与 `--purge`(清除配置与数据)。
* **Docker 安装**:卸载是容器命令,与安装脚本的参数无关——`docker rm -f flashduty-runner`(卸载,保留 `/var/flashduty/workspace` 数据)与 `docker rm -f flashduty-runner && rm -rf /var/flashduty/workspace`(彻底卸载,同时清除 workspace 数据)。
## 权限配置
***
Runner 默认使用允许全部命令的规则,这与直接在自己的 shell 里运行 AI 模型、信任模型的判断是同一套信任模型:
```yaml theme={null}
permission:
"*": "allow"
```
当您希望把 Runner 的命令执行范围收敛到允许列表或拒绝列表时,可以在 Runner 所在机器上创建一个 YAML 文件,并通过 `--permission-config` 参数或 `FLASHDUTY_RUNNER_PERMISSION_CONFIG` 环境变量指定它。权限配置是 Runner 本机文件,不在控制台表单里编辑。
Linux (systemd) 安装后,推荐在 `/etc/flashduty-runner/env` 中加入:
```bash theme={null}
FLASHDUTY_RUNNER_PERMISSION_CONFIG=/etc/flashduty-runner/permission.yaml
```
然后重启服务:
```bash theme={null}
sudo systemctl restart flashduty-runner
```
手动启动时也可以直接传参数:
```bash theme={null}
flashduty-runner run \
--token \
--permission-config /etc/flashduty-runner/permission.yaml
```
权限配置会在 Runner 启动时加载。修改 YAML 后需要重启 Runner,新的规则才会生效。
规则文件顶层键是 `permission`,值是 **glob 模式 → `allow`/`deny`** 的映射:
```yaml theme={null}
permission:
"*": "deny"
"kubectl get *": "allow"
"kubectl describe *": "allow"
"cat *": "allow"
```
规则语义:
* 不设置 `--permission-config` / `FLASHDUTY_RUNNER_PERMISSION_CONFIG` 是默认行为,等价于允许所有命令;
* 规则会应用到命令的每一处出现——管道(`cmd1 | cmd2`)、`$(...)`/反引号命令替换、进程替换、算术展开,以及写入重定向目标(例如 `echo x > /etc/passwd` 会像执行命令一样被拦截;读重定向本身不会额外拦截);
* 命令按规范化后的 shell 片段匹配,空格差异不会影响匹配;
* **最具体的规则优先**:第一个 `*` 之前字面前缀最长的模式最先被尝试匹配,兜底规则 `"*"` 始终最后尝试,第一个匹配的规则生效;
* 该文件仅在 Runner **启动时加载一次**——修改规则后需要重启 Runner,新规则才会生效,不支持热重载;
* 若指定了该 flag/环境变量,但文件缺失、格式错误,或未在 `permission` 键下定义任何规则,Runner 会**拒绝启动**(fail closed),而不是静默放行所有命令:显式配置权限即代表明确希望限制执行范围,配置写错时应当报错而非留下安全隐患。
默认拒绝所有命令,仅显式放行需要的命令:
```yaml theme={null}
permission:
"*": "deny"
"kubectl get *": "allow"
"kubectl describe *": "allow"
"kubectl logs *": "allow"
"cat *": "allow"
"ls *": "allow"
```
等价于完全不设置 `--permission-config`,但允许显式声明例外:
```yaml theme={null}
permission:
"*": "allow" # 信任 AI 模型
"rm -rf /": "deny" # 如需要可阻止灾难性命令
```
适用于 Runner 运行在隔离 VM/容器、影响范围有限,或更看重响应速度而非限制权限的场景。
只放行只读命令,适合仅用于观测、不希望 Runner 修改任何状态的场景:
```yaml theme={null}
permission:
"*": "deny"
"cat *": "allow"
"head *": "allow"
"tail *": "allow"
"ls": "allow"
"ls *": "allow"
"grep *": "allow"
"ps *": "allow"
"df *": "allow"
"free *": "allow"
"pwd": "allow"
"whoami": "allow"
"date": "allow"
```
命令权限当前仅支持通过配置文件设置,控制台暂无对应的可视化配置界面。
## 在会话中选择环境
***
聊天输入框底部的环境选择器决定新会话在哪里执行:
| 选项 | 含义 |
| ------------------- | ------------------------------------------------------------------------------------------------------------------ |
| **自动** | 新会话默认值。优先使用当前成员可用的在线 Runner,否则回退到云端 Sandbox。 |
| **云端 Sandbox · 默认** | 强制使用系统托管的云端 Sandbox,忽略自托管 Runner。 |
| **自托管 Environment** | 列出当前成员可使用的 Runner。离线、从未连接或团队权限不匹配的 Runner 不可选;处于 **性能下降(degraded)** 的 Runner **仍然可选**,选中后会提示「性能下降 — 可继续使用,响应可能变慢」。 |
环境选择对一条会话是一次性锁定的:会话首次发送消息时确定的运行环境会被记录,后续轮次始终沿用,不会因为您之后切换选择器而改变。要换环境,请新建会话。
历史会话打开时,选择器会以只读形式展示这条会话当初锁定的环境及其当前状态。如果绑定的 Runner 已离线或被删除,该会话不能继续发送消息;请先恢复 Runner,或新建会话改用云端 Sandbox。
## 作用域
***
每个 BYOC Environment 都有账户级与团队级两档作用域:
| 作用域 | 可见范围 |
| --- | ----------------------- |
| 账户级 | 整个账户内所有成员可见、可选择并可用于运行。 |
| 团队级 | 仅该团队成员可见、可编辑、可选择并可用于运行。 |
编辑权限遵循统一规则:
1. 账户所有者或账户管理员可编辑任意 Environment;
2. 团队成员可编辑本团队的团队级 Environment;
3. 不存在“创建者额外权限”,不是创建者也可以按上述规则编辑。
账户仍是运行时安全边界,但团队作用域也会参与 Runner 选择:系统自动选择 Runner 或按 ID 固定 Runner 时,只会使用账户级 Runner,或当前成员所属团队下的团队级 Runner。这样可以避免成员把会话落到自己无权使用的团队 Runner 上。
## 故障排查
***
排查 Runner 问题时,先看 Environments 列表的**状态**与**最后心跳**。
离线说明 Runner 曾连接过,但 AI SRE 在约 90 秒内没有收到心跳。请检查 systemd 服务或进程是否在运行、机器是否休眠或断网、到 AI SRE 的出网是否被防火墙阻断。恢复进程和网络后,Runner 会自动重连。
等待中说明这条 Environment 从未成功连接过。请确认安装命令完整执行、Token 属于这条 Environment、`URL` 从目标机器可达。如果使用了权限配置,也要确认配置文件存在且 YAML 可解析。
私有化端点的证书未被 Runner 信任。优先把签发该证书的 CA 加入 Runner 所在系统或容器的信任库;如果端点使用自签证书且位于可信私有网络内,也可以按上文说明显式开启 `FLASHDUTY_RUNNER_INSECURE_SKIP_TLS_VERIFY`。systemd 部署需要重启服务,Docker 部署需要用新的环境变量重新创建容器,手动运行的进程需要重新启动。
如果会话固定到了某个离线 Runner,AI SRE 不会偷偷改派到其他环境。请先恢复该 Runner,或新建会话并选择“自动”或“云端 Sandbox”。如果 Runner 在线但任务失败,多半是 Runner 到目标资源这一段的网络或权限问题。
最快的定位方法:**离线 / 等待中**看 Runner 到 AI SRE 的连接;**在线但执行失败**看 Runner 到目标资源的网络、凭据和权限。
## 相关页面
***
了解云端 Sandbox 的生命周期、适用场景与出网边界。
在会话中查看绑定的运行环境、团队与 Agent 调用的资源。
MCP 连接在 Agent 运行时于所选环境内建立。
Skill 在所选运行环境中执行。
# IM 平台
Source: https://docs.flashduty.com/zh/ai-sre/im
AI SRE 是 IM 原生的——在 Slack、飞书、钉钉、企业微信的群聊或私聊里 @ 它即可发起或续接排查,它在线程内作答;为故障开启作战室时可按集成设置自动跑一轮初步诊断并回贴。
**公测功能**:AI SRE 已全量开放公测,无需申请,登录控制台即可直接使用,公测期间免费。功能与界面可能继续调整。
## 概述
***
排障往往就发生在你的 IM 群里——告警推过来、大家在群里讨论、拉个作战室。AI SRE 把 Agent 直接放进这条协作链路:**你不必切换到控制台,就能在 IM 里召唤它排查**,团队成员也能全程看到它的分析过程。
AI SRE 的 IM 集成有两种触发方式:
在群聊或私聊里 **@ AI SRE** 并描述问题,即可发起或续接一次排查。它在**线程内**回答,对话上下文与这条 IM 会话绑定。
为故障开启 IM 作战室时,若该集成保留默认开启的 **自动发起 AI 故障分析**,AI SRE 会跑一轮初步诊断,并把结论作为一条分析消息回贴到作战室——无需任何人手动召唤。
## 支持的 IM 平台
***
AI SRE 的 IM 交互覆盖四个主流平台,每个平台都支持入站的 @ 提及(webhook)、历史消息读取与出站回复:
| 平台 | 群聊 @ 提及 | 私聊(DM) | 作战室自动诊断 |
| ------------- | ------- | ------ | ------- |
| Slack | ✅ | ✅ | ✅ |
| 飞书 / Lark | ✅ | ✅ | ✅ |
| 钉钉 / DingTalk | ✅ | ✅ | ✅ |
| 企业微信 / WeCom | ✅ | ✅ | ✅ |
IM 交互依赖你已在 Flashduty 中接入对应平台的机器人(用于告警通知与协作的同一套 IM 机器人)。请先在 Flashduty 的 IM 集成中完成机器人配置,AI SRE 才能在该平台收发消息。
## IM 集成中的 AI SRE 设置
***
在 **On-call → 集成中心 → 集成列表 → 即时消息** 打开对应 IM 集成详情,在 **增强功能** 中分别配置该集成的 AI SRE 行为。以下开关默认均为开启:
* **自动发起 AI 故障分析**:开启作战室后可配置;集成成功创建作战室时,自动发起一次 AI SRE 初步诊断并把结果回贴到作战室。
* **允许群聊 @ AI SRE**:无需开启作战室即可配置,允许群聊中的 @ 提及进入 AI SRE。Slack 中该开关显示为 **允许群聊 @ AI SRE 和 /fd 命令**;关闭后,群聊 @ 提及和 `/fd` 命令都不会触发 AI SRE。
* **普通群聊中 AI SRE 使用话题回复**:仅飞书/Lark 与 Slack 提供。开启后,普通群聊中的每个话题对应一个独立 Session;作战室仍直接在群内回复。
若账户尚未开通 AI SRE,这些开关不会实际生效;开通后会按各 IM 集成自己的设置生效。
## @ 提及召唤
***
在已接入且允许群聊 @ AI SRE 的 IM 群里 **@ 机器人** 并写下你的问题(例如「@AI SRE 看下 payment 服务为什么 5xx 飙升」),消息会通过平台 webhook 转给 AI SRE 处理:
平台区分**群聊 @ 提及**与**私聊消息**两种入口。被提及后,AI SRE 会做去重,并识别消息里是否带有命令式指令。
AI SRE 以「账户 + 平台 + 会话(chat)」为键定位一个会话:同一个 IM 会话里的多次 @ 提及,会续接到**同一个 Agent 会话**,从而保留上下文。若是新会话,平台会带入该 IM 线程的起始消息、以及(若有)关联的故障作为初始上下文。
AI SRE 读取线程 / 会话的历史消息构建上下文,自主排查,并把结论**在线程内**回复。消息里一并 @ 到的其他人也会被保留为提及对象,在回复中带上,方便多方在群里协作。
**回复模式**可配置(off / first / all),决定 AI SRE 是否在回复时 @ 提问者、以及是在**线程内**还是主频道作答。在嘈杂的大群里,线程内回复能让排查讨论保持聚拢、不刷屏。
## 作战室自动诊断
***
当你为一个故障在 IM 中开启**作战室**(war room)且该集成保留 **自动发起 AI 故障分析** 开关时,AI SRE 会自动介入——无需任何人 @ 它:
在故障的协作流程中创建作战室(飞书 / 钉钉 / 企业微信 / Slack 群)。
作战室建好后,平台会以**非阻塞后台任务**触发一轮初步诊断,让 AI SRE 带着该故障的上下文进入排查。
诊断完成后,AI SRE 把分析结果作为一条消息发回作战室。人还没开始排查,第一手分析就已经摆在群里了。
作战室自动诊断与故障上下文绑定:进入排查时,对应的 `incident_id` 会绑定到本次运行,AI SRE 可据此读取故障详情、时间线与近期变更。关于故障 / 作战室与 A2A 的联动细节,见 [Agent · 故障与作战室联动](/zh/ai-sre/agents#故障与作战室联动)。
## IM 会话内切换命令
***
IM 会话没有控制台那样的选择器 UI,但支持两条斜杠命令在**对话进行中**动态切换绑定——控制台会话不支持这两个操作,其环境与团队绑定在创建时固定、不可变更。
### /env — 切换运行环境
在群聊或私聊里向机器人发送 `/env `,可将当前 IM 会话重新绑定到另一台在线的 BYOC Runner,对话历史与上下文完整保留。切换后,旧环境的工作目录不再可用:本次对话中在旧环境里创建或修改的文件已丢失,技能与知识包文件会在新环境中按需重新挂载。
切换在当前轮次结束、下一条消息处理之前生效,不会打断正在进行的工具调用。若目标 Runner 离线或不存在,命令会立即报错且绑定不变。
### /scope — 切换团队作用域
在群聊或私聊里向机器人发送 `/scope <团队名>`(或 `/scope personal` 切回个人作用域),可将当前 IM 会话重新绑定到指定团队,无需结束对话并新建会话。团队绑定是**使用权操作**,账户内任意成员均可将会话绑定到账户内的任意团队——这与作战室中响应人员通常不属于故障所属团队的场景一致。
切换后,AI SRE 会:
1. 将记忆快照刷新为新团队作用域下的记忆(旧团队的记忆不再适用于本次会话)。
2. 把新团队的知识包排入挂载队列,在下一条消息处理时自动注入上下文。
已挂载到本次会话的知识包不会被移除——挂载是对话级别的,切回之前挂载过的团队不会重复注入提醒。
## 与控制台会话的关系
***
无论从 IM 还是控制台发起,**都是同一个 AI SRE**:按顺序处理消息、流式输出、长对话自动压缩上下文、可绑定团队与运行环境。区别只在入口——
* **控制台**:在「对话」工作区里逐条提问、查看完整的工具调用与子会话面板;环境与团队绑定在创建时固定,后续不可变更。
* **IM**:在你日常协作的群里 @ 召唤,结论回贴到线程;支持 `/env` 和 `/scope` 命令在对话中途动态切换绑定,适合在故障现场快速拿到分析,再到控制台深入。
会话的更多细节见 [对话](/zh/ai-sre/sessions)。
## 相关页面
***
了解 AI SRE 的整体能力、典型场景与控制台导航。
了解会话、流式输出、取消与上下文压缩。
入站 Agent Card 与故障 / 作战室联动。
用 /insight 复盘近 30 天会话,发现运维摩擦。
# 初始化(/init)
Source: https://docs.flashduty.com/zh/ai-sre/init
在 AI SRE 会话中输入 /init,由 Agent 以访谈的方式带你从零搭建运维知识库(DUTY.md + runbook + 服务清单等)并按需接入 MCP——每一项写入都需你逐条确认。
**公测功能**:AI SRE 已全量开放公测,无需申请,登录控制台即可直接使用,公测期间免费。功能与界面可能继续调整。
## 概述
***
在任意 AI SRE 会话的输入框中输入 `/init`,Agent 会切换成一名**运维 onboarding 访谈者**,带你从零搭建一份运维知识库——也就是这个团队的「运营作战图」。它会扫描你的 Flashduty 故障与通知渠道、向你提问、把你口述的服务拓扑、排查手册、集群访问方式等沉淀成知识文件,并在需要时帮你接入外部工具(MCP)。
`/init` 是知识库的**起点**。AI SRE 的诊断质量直接取决于它能读到多少关于你系统的真实知识:[知识库](/zh/ai-sre/knowledge)维护得越完整、越准确,Agent 定位根因就越快、越靠谱。`/init` 就是把这份知识从零建立起来的引导流程,建完之后每一次会话都会自动加载它。
`/init` **不会**在未经你同意的情况下写入或安装任何东西。每个阶段在写入文件前都会列出「将要创建/更新哪些文件」的清单,由你逐条确认后才执行。凭证(token、密码、AK/SK)永远不会在对话里明文回显,只记为 `<已记录(长度=N)>`。详见 [安全与同意](#安全与同意)。
## 何时用 /init,何时直接说
***
`/init` 解决的是**结构化的从零搭建 / 系统性补全**;零散的小修小补不需要它。
| 场景 | 用法 |
| ---------------------------------------- | ------------------------------------------------- |
| 第一次给某个账户 / 团队搭知识库 | **`/init`**——它会成体系地走完服务、可观测性、runbook、常见故障、集群访问等主题 |
| 系统性地补全或重整一个已有知识库 | **`/init`**——可随时重跑,它会基于现有内容继续,而非推倒重来 |
| 「补一篇 runbook」「更新 services.md」「记一下这个故障模式」 | **直接用自然语言说**,无需 `/init`——Agent 会就当前会话作用域读取、编辑、保存 |
`/init` 与零散的自然语言编辑是互补的:用 `/init` 把底子打全,之后在日常排障里随手让 Agent「把这条经验记进知识库」做增量维护。两者写入的是同一个知识库。
## 如何运行
***
在任意一个 AI SRE 会话的输入框输入 `/init` 并发送。无需参数。
`/init` 先锁定本次要写入的范围:**账户级**(账户内所有会话可见)或**某个团队级**(仅该团队会话加载)。范围由当前会话是否绑定团队决定,Agent 会先反问你确认;一次会话只锁定一个范围,中途不切换。
Agent 按主题逐阶段提问(服务与拓扑、可观测性、runbook、常见故障、集群访问……),把你的回答整理成知识文件草稿。每个阶段结束都会问你「继续下一项,还是先停在这里」。
每个阶段写入文件前,Agent 会给出一份「将创建/更新哪些文件」的清单,每个文件配 3–5 行摘要。你确认后它才写入知识库,并把新文件链接进 `DUTY.md` 目录。
你可以随时说「跳过这项」「回到第 N 步」「先到这里」。`/init` 不是一次性的——之后任何时候重新输入 `/init` 都能基于已有知识继续补全。
## 访谈流程
***
`/init` 按固定顺序走一套阶段,每个阶段有明确的进入与退出条件。你可以随时跳过、回退或叫停。
读取当前会话绑定的团队:若绑定了团队,本次 `/init` 落在该团队级;若是账户级会话,则落在账户级(对所有团队可见)。Agent 会先和你确认这一点,确认后整场会话固定使用这个范围。想换团队范围,需退出后从目标团队重新打开 `/init`。
通过 Flashduty MCP 拉取你的渠道、近 30 天故障、团队与成员,归纳出你在用的集成类型与高频故障标签。若扫描结果为空(全新账户),切换到「冷启动」模式,改为完全靠访谈采集。
可选步骤,需你主动同意,绝不自动触发。如果你已经在 Claude Code / Codex / Cursor / Windsurf / Copilot / Gemini CLI 等本地工具里积累了知识与记忆,可一次性导入,避免后续被反复追问。当 Runner 能直接访问到这些文件时(装在你本机的自托管 Runner),Agent 直接读取 `~/.claude/CLAUDE.md`、各仓库的 `CLAUDE.md` / `AGENTS.md`、`.cursor/rules`、记忆库等;否则(云端沙箱或装在另一台机器上)Agent 给你两段通用提示词,你在本地工具里运行后把结果粘贴 / 上传回来。导入内容按其性质分流:运维 / 服务知识写入知识库文件,个人偏好 / 可复用习惯写入 Agent 记忆,重复或无用的则丢弃。所有导入内容在预览或写入前都会先做**密钥脱敏**,密钥永远不会落盘。
Agent 用一段话回述它看到的画面:「我看到 N 个渠道、近 30 天 M 个故障、你似乎在用 \[列表]、高频标签包括 \[列表]。对吗?还缺什么?」等你确认或纠正,**此时还不写入任何文件**。
按主题逐阶段采集并成文,每一阶段都遵循「采集 → 草拟文件 → 出清单预览 → 你确认 → 写入并更新 DUTY.md 目录」:
| 阶段 | 主题 | 产出 |
| -- | ---------- | ------------------------------------------ |
| 3 | 服务与拓扑 | `services.md`(+ 可选 `topology.md`) |
| 4 | 可观测性栈 | `observability.md` + 在 `tools.md` 登记相关 MCP |
| 5 | 运行手册 | `runbooks/<主题>.md`,一类故障一文件 |
| 6 | 常见故障 | `common-failures.md` |
| 7 | 集群访问与运行时探查 | `clusters.md`(k8s)/ 追加到 `tools.md`(MCP) |
阶段 7 中,**原生 kubectl 是首选的集群访问方式**,k8s-MCP 为兜底(同一集群二者不同时配置)。该路径仅适用于自托管 Runner:在 Runner 上为每个集群放置一份**只读** kubeconfig(`<工作区>/.kube/<名称>.config`),`clusters.md` 只记录其**路径**,绝不记录 token。
当你表示完成时,Agent 给出一段小结:本次创建/更新了哪些文件、登记了哪些 MCP,并提示「任何时候重跑 `/init` 都能继续」。知识库本身就是这次会话的持久成果。
## 安全与同意
***
`/init` 会写知识、可能装 MCP、还会碰到凭证,因此同意与最小权限是它的硬性约束:
任何写入或安装都必须经你明确同意。每个采集阶段在写入文件前都会列出「将创建/更新哪些文件」的清单(每项配 3–5 行摘要),你点头后才执行——绝不会拿一句模糊的「好」直接触发写入。
当你提供 token、密码、AK/SK 等敏感信息时,Agent 只确认「已记录(长度=N)」,绝不在对话里重复打印明文。
每当需要你提供或生成凭证(kubeconfig、云 AK/SK、数据库账号、API token),Agent 都会要求你按**只读 / 最小权限**来配置;在边界可机器校验时,它会先做一次只读边界检查再记录。
不是所有信息都值得写进知识库。Agent 只写「缺了它,AI 在故障里会做出更糟决定」的内容——可有可无的细节不会被塞进去,避免知识库变臃肿。
## 产出什么
***
`/init` 的成果是一份可被后续每次会话自动加载的[知识库](/zh/ai-sre/knowledge):
* **`DUTY.md`**——知识库的目录入口,只放一句话导引和一份 `@文件名` 链接清单,指向各主题文件;
* **主题文件**——`services.md`、`topology.md`、`observability.md`、`runbooks/<主题>.md`、`common-failures.md`、`clusters.md` 等,实质内容都在这里;
* **MCP 登记**(可选)——若访谈中接入了外部工具,会在 `tools.md` 记录并完成 MCP 服务器注册。
`/init` 的主要产出是**知识**,不是 Skill。它不会把内容存成 Skill,除非你明确要求。它也不会自动安装 Agent——这类资源目前需你在控制台手动添加。
## /init 与 /insight:一对最佳实践
***
`/init` 和 [`/insight`](/zh/ai-sre/insight) 是运维知识「建立 → 打磨」闭环的两端:
从零把知识库搭起来:服务、拓扑、runbook、集群访问一次成体系地沉淀,让 Agent 一上来就懂你的系统。
回看近 30 天会话,找出反复粘贴的上下文、缺失的 runbook、用错的数据源,告诉你**下一步该往知识库里补什么**。
推荐的节奏:先用 `/init` 打好底子,跑几次真实排障后再用 `/insight` 复盘,把它指出的摩擦补回知识库——必要时重跑 `/init` 做系统性整理。知识库越完善,AI SRE 越精准好用。
## 相关页面
***
`/init` 的产出落在这里——了解 DUTY.md 结构、文件约束,以及如何手动编辑与维护。
用 `/insight` 复盘会话、发现运维摩擦,指导你持续补全知识库。
`/init` 可在访谈中帮你接入的外部工具,了解 MCP 的连接与管理。
# 使用洞察(/insight)
Source: https://docs.flashduty.com/zh/ai-sre/insight
在 AI SRE 会话中输入 /insight,自动分析您近 30 天的会话,产出一份只读的教练式月度复盘——先讲做得好的地方,再讲值得消除的摩擦,最后给出更高杠杆的下一步建议。
**公测功能**:AI SRE 已全量开放公测,无需申请,登录控制台即可直接使用,公测期间免费。功能与界面可能继续调整。
## 概述
***
在任意 AI SRE 会话的输入框中输入 `/insight`,AI SRE 会回看**您**近 30 天的会话,产出一份单页的运营洞察报告。报告采用羊皮纸样式的 HTML,会作为聊天卡片直接渲染在会话中,您可以预览和下载。
这是一份**教练视角的月度复盘**,而不是一张问题清单:它先讲**做得好的地方**——这一个月 AI SRE 在哪些地方真正帮上了忙;再讲**值得现在就消除的摩擦**——那些一再消耗您时间的模式,比如同一个数据库连接串您在多个会话里反复粘贴、Agent 缺少某个本该已知的排查手册、或它反复查错了数据源;最后给出 **2–3 条更高杠杆的下一步建议**——在「怎么用 AI SRE」这件事上可以尝试的方向。
`/insight` 是**只读**的。它只做分析和呈现,**不会**自动改动任何知识库、Skill 或 MCP 配置。每一条建议都是可复制的文本,是否采纳由您决定。详见 [如何处理建议](#如何处理建议)。
`/insight` 是 AI SRE 内置的一项 Skill:它会自动导出你的历史会话、统计量化指标、逐段分析会话内容,最后汇总渲染成一份报告。整个过程对您透明,您只需要输入 `/insight`。
## 如何生成
***
在任意一个 AI SRE 会话的输入框输入 `/insight` 并发送。无需任何参数。
范围由当前会话是否绑定团队决定(见下表),AI SRE 会在报告开头告知本次分析的范围与时间窗口(默认近 30 天)。
AI SRE 会导出会话、计算指标、分析内容,然后把羊皮纸样式的报告作为聊天卡片渲染出来,并附上一段 2–3 句的口头小结。您可以在卡片里预览或下载完整报告。
### 分析范围
`/insight` 始终以**账户**为安全边界——它只会看到当前 `app_key` 有权读取的会话,绝不越界。在此前提下,具体范围由会话是否绑定团队决定:
| 会话状态 | 分析范围 | 说明 |
| --------------------------- | -------- | ------------------- |
| 已绑定某个团队(如作战室 / 在 UI 中选定了团队) | **该团队** | 报告会聚焦这一个团队近 30 天的会话 |
| 未绑定团队 | **整个账户** | 分析您自己的会话,以及您所属团队的会话 |
当会话未绑定团队、而您其实只想看某一个团队时,可以在输入 `/insight` 时直接点名该团队(团队名称或 ID),AI SRE 会反问确认后再把范围收窄到那个团队。
### 报告是怎么来的
了解分析流程有助于您理解报告里的数字从何而来:
AI SRE 先列出范围内近 30 天的会话(默认最多 200 个),覆盖**全部四种入口**——网页(web)、IM、API、自动化(automation);IM 是 AI SRE 的主要入口之一,因此 IM 触发的会话也会一并纳入分析。导出完整记录后,保留**有真实信号**的会话:**用户消息 ≥ 2 轮,或工具调用 ≥ 3 次**(二者满足其一即可,对应 `INSIGHT_MIN_MSGS` / `INSIGHT_MIN_CALLS`)。「工具调用」这一条很关键——它让那些由告警或定时触发的自主会话(可能没有任何人工轮次,却做了十几次工具调用的真实排查)也能进入报告,而不会被「只看人工轮数」的旧规则误删。报告还会在量化总览里给出一行**会话来源**(`entry_mix`),让您看到这些会话分别来自哪些入口。
报告的量化总览——会话数、您的轮数、工具调用数、平均轮数、按天的活跃度、工具与 Skill 分布、会话来源、模型分布、结果分布——由程序在所有会话上确定性地统计得出,而非由模型估计,因此可靠且始终存在,即便没发现任何摩擦也照常呈现。
AI SRE 分段阅读会话记录,从每一段提炼出「会话主题」「做得好的地方」与「摩擦发现」,再把全部结果汇总:主题聚合成叙事概述,做得好的地方挑出最有代表性的几条,摩擦发现去重、聚类并按重要度排序成摩擦卡片。每条结论都配一句**逐字引用**作为证据;会话 ID 仅在内部用于统计某个摩擦重复出现的次数,**不会**展示在报告里。报告只包含提炼出的主题与发现,不会逐字搬运您的整段原始会话内容。
## 报告内容
***
报告自上而下分为**六个部分**。无论是否发现摩擦,量化总览始终呈现。
### 1. 一句话综述(At a glance)
报告最顶部的 **2–4 句**教练式综述,是在其余部分都写完之后最后落笔的,把整个月浓缩成要点:总量与主题、做得最好的那件事、以及最值得先解决的那个摩擦。
### 2. 量化总览(Overview)
由程序确定性计算,而非模型估计;模型只负责把数字誊写进报告。包含:
| 指标 | 说明 |
| -------- | ------------------------------------------------------------- |
| 会话数 | 本次分析的会话数量(`sessions`) |
| 您的轮数 | 这些会话里您发出的消息总轮数(`your turns`) |
| 工具调用数 | Agent 发起的工具调用总数(`tool calls`) |
| 平均轮数 | 每个会话的平均轮数(`avg turns / session`,保留一位小数) |
| 活跃度 | 按天的会话活跃柱状图,标出起止日期 |
| 工具分布 | Agent 最常依赖的工具排行(取前 \~6 项) |
| Skill 分布 | 会话中调用过的 Skill 排行;若没有调用过任何 Skill,则显示「未调用任何 Skill」 |
| 会话来源 | 这些会话分别来自哪些入口,形如 `web(60)· IM(25)· automation(5)`(`entry_mix`) |
| 模型分布 | 各模型各被多少个会话使用,形如 `模型名(N 个会话)` |
| 结果分布 | 完成 / 未完成 / 出错的会话数(某项为 0 时省略) |
### 3. 叙事概述(Narrative)
用 **2–4 句**第二人称的话,概括您这一个月主要在做什么——最常处理的领域、反复出现的实体(被分析两次的同一个故障、反复出现的某个集群或主机),以及整月工作的大致形态。这部分由各会话提炼出的主题聚合而来。
### 4. 做得好的地方(What's working)
挑出约 3 条 AI SRE **做得好**的、有证据支撑的事——比如跨数据源交叉验证、正确的噪声分级、干净利落的根因定位。这部分平衡了整份报告,只要有真实亮点就不会跳过;每条都配一句逐字引用作为佐证。
### 5. 摩擦卡片(Frictions)
按重要度**从高到低排序**的摩擦卡片,最多约 8 张。每张卡片包含:
* **排名**与**摩擦类型标签**(五类之一,见下节);
* 一个**频次徽标**,表示这个摩擦在多少个不同会话里消耗过您(去重后的证据会话数);
* 一句话标题与一段第二人称的解释;
* **证据**:一句来自会话记录的**逐字引用**(最能说明问题的那句用户或 Agent 的话);会话 ID 仅用于内部去重计数,**不展示**;
* **可复制的建议**:一段可直接粘贴的文本,其第一行即落点(`Add this to knowledge/<范围>/…`),把目标文件随复制一并带走。
### 6. 下一步建议(Next steps)
约 **2–3 条**面向未来、有据可依的建议。它们是**策略层面**的(在「怎么用 AI SRE」上更高杠杆的转变),区别于摩擦卡片那种逐文件的战术修复;每条都点明它所依据的具体观察(某个总览数字或某一类摩擦),并对应一项真实存在的 AI SRE 能力。
每条摩擦与亮点都必须扎根于至少一个真实会话,并配一句逐字引用作为证据——报告不会凭空捏造会话、事实或排查手册缺口。如果没有发现任何可排序的摩擦,摩擦部分会显示一段空状态提示,而其余部分照常呈现——此时「总览本身就是报告」。
## 摩擦类型
***
`/insight` 只识别五类摩擦,每一类都对应一个明确、可调整的「旋钮」。按默认重要度排序如下:
| 摩擦类型 | 在会话里的样子 | 建议落点 |
| --------------------------- | -------------------------------------------------------------------------- | ---------------------------------------------- |
| `repeated_context`(重复上下文) | **信号最强。** 某个长期有效的事实,您在 **≥ 2 个不同会话**里反复提供(数据库连接串、服务归属的团队、看板 URL、升级路径、集群名等) | 写进 DUTY.md / `services.md`,让它每次会话自动加载 |
| `missing_runbook`(缺少运行手册) | Agent 不得不临时拼凑一套多步排查,而您显然期望它本就该会 | 新增运行手册:`knowledge/<范围>/runbooks/<主题>.md` |
| `wrong_data_source`(数据源用错) | Agent 查了错误的数据源 / 集群 / 命名空间,被您纠正 | 在 `observability.md` / `clusters.md` 里固定正确的数据源 |
| `hallucinated_entity`(臆测实体) | Agent 引用了一个并不存在的服务 / 主机 / 指标 / 变更,被您否定 | 把真实的实体清单补进 `services.md` |
| `stale_knowledge`(知识过期) | 来自知识库 / DUTY.md 的某个事实已经过时或错误,被您当场纠正 | 更新那个过期的文件 |
`repeated_context` 之所以排在首位,是因为它**最持久**——同一个事实跨多个会话被反复提供,意味着把它沉淀进知识库一次,未来每个会话都能直接受益。当它的证据数与其他摩擦持平时,也优先排在前面。
## 如何处理建议
***
报告是**只读**的:它呈现问题、给出可复制的修复文本,但**绝不**自动应用任何改动。公测期间所有建议都是复制粘贴式的,需要您确认后,再到对应的资源里手动修改。
摩擦卡片已按重要度排好序。优先看排名靠前、频次徽标数字高的那几张——它们是最反复消耗您时间的模式。
每张卡片的「可复制的建议」里是一段可直接粘贴的文本,其第一行(`Add this to knowledge/<范围>/…`)就是落点,告诉您它该写到哪个文件——复制时会把目标路径一并带上。
根据摩擦类型,到相应的资源里粘贴并保存:重复上下文与臆测实体写进知识库的 `services.md` 或 DUTY.md;缺少运行手册则在知识库里新增一份 runbook;数据源用错就固定到 `observability.md` / `clusters.md`;知识过期则直接更新那个文件。这些都属于 [知识库](/zh/ai-sre/knowledge) 的常规编辑。
`/insight` 永远不会替您执行写入——它不调用任何同步/安装动作,也不改动知识库、Skill 或 MCP。如果您后续想让 AI SRE「把这条 runbook 加进去」,那是一次**独立**的自然语言指令,不属于 `/insight` 的范围。
`/insight` 按需运行、一次一份——它不会「持续盯着」或定时生成报告。建议在又积累了几次故障排查之后再跑一次,看看哪些摩擦已被消除、又冒出了哪些新的。
## 相关页面
***
了解会话的创建、团队绑定与作战室——这些决定了 `/insight` 的分析范围。
报告里的建议大多落在知识库的 DUTY.md / `services.md` / runbooks,这里讲如何编辑。
从整体了解 AI SRE 的能力与运行机制。
`/insight` 生成的报告本身就是一种产物,发布后可以在产物库里统一查看与分享。
# 管理知识
Source: https://docs.flashduty.com/zh/ai-sre/knowledge
为 AI SRE 提供账户与团队的运维知识——一份 DUTY.md 加运行手册、FAQ、服务清单、集群配置等文件,Agent 在会话中按需读取并挂载。
**公测功能**:AI SRE 已全量开放公测,无需申请,登录控制台即可直接使用,公测期间免费。功能与界面可能继续调整。
## 概述
***
知识库(Knowledge Pack)是您交给 AI SRE 的运维知识:一份 `DUTY.md` 加上一组运行手册(runbook)、FAQ、服务清单、集群配置等文件。会话开始时,Agent 先读取 `DUTY.md`,再顺着其中的引用按需取用相关文件,从而把您团队的处置经验、命名约定与系统拓扑带进每一次诊断。
每个**目标**(账户或团队)最多拥有一个 Knowledge Pack:
* **账户级**知识对账户内所有 Agent 可见。
* **团队级**知识仅在该团队的会话中加载,仅对该团队成员可见。
Knowledge Pack 是 AI SRE 资源的一种,遵循统一的两级作用域模型。其他资源(Skill、MCP、Agent、运行环境)的作用域规则与本页一致。
知识库内容用于**精炼**Agent 的领域上下文(人设、方法论、系统知识),但不会覆盖系统的安全与行为底线。如果某份知识要求 Agent 跳过安全规则,会被当作越权内容忽略,而非更高优先级的指令。
## DUTY.md 结构
***
`DUTY.md` 是整个知识库的**目录入口**。它本身就是清单——Agent 会全文读取 `DUTY.md`,再通过 `@文件名` 引用按需拉取其它文件。`DUTY.md` 存在时,系统不会在其之外另附一份文件列表;目录即正文。
如果某个作用域还没有 `DUTY.md`、但已有其它知识文件,该作用域不会被静默跳过:系统会在会话知识清单中附上一份自动生成的权威文件索引,并明确指示 Agent 在开展实质工作前,先阅读索引中与当前任务相关的文件(文件不多时应全部读完),而不是跳过这一步直接下结论。创建 `DUTY.md` 之后,这份生成索引的引导即随之消失,恢复「目录即正文」。
引用采用 `@<路径>` 风格,路径指向同一个 Pack 内的另一份文件,支持子目录(如 `@runbooks/api-5xx.md`):
```markdown theme={null}
# 值班知识总览 (DUTY.md)
## 服务清单
我们的核心服务与负责人见 @services.md。
## 常见故障处置
- API 5xx 飙升:参见 @runbooks/api-5xx.md
- 数据库连接池打满:参见 @runbooks/db-pool.md
## 集群与环境
生产集群拓扑与访问方式见 @cluster.yaml。
```
Agent 读取 `DUTY.md` 后,会根据当前故障判断需要展开哪些 `@引用`,再去读对应文件——实质内容放在被引用的兄弟文件里,`DUTY.md` 只承载链接列表。
这套分层 `@reference` 架构让 `DUTY.md` 保持精简、可读。`DUTY.md` 像一张地图,运行手册、服务清单、配置则是它指向的详情页。Agent 不必把所有文件一次性塞进上下文,只在需要时才展开相关分支。
**文件约束**(在创建与编辑时强制):
| 约束 | 取值 | 说明 |
| ---------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 文件内容 | 纯文本(UTF-8) | 按**内容**校验而非扩展名:文件不含 NUL 字节且能按 UTF-8 解码即可保存。因此 `.md` `.yaml` `.json` `.txt` `.sh` 之外的 `.py` `.sql`,乃至没有扩展名的 `Dockerfile` 都可以上传;反之,扩展名是 `.txt` 但内容为二进制的文件会被拒绝 |
| 单文件上限 | 1 MiB | 超出无法保存 |
| 单个 Pack 上限 | 5 MiB | 控制台用量条按此额度显示 |
| 文件数量上限 | 100 | 达到上限后无法新增文件 |
| 子目录 | 允许 | 路径可含 `/`,如 `runbooks/api-5xx.md`;不允许以 `.` 开头的路径段 |
| 点文件 | 不允许 | 文件名不能以 `.` 开头 |
## 创建与编辑
***
进入 **知识库**(Knowledges)管理页,您可以为账户或团队创建、编辑、启用/禁用、删除 Knowledge Pack。列表按 **名称 / 范围 / 文件 / 状态 / 操作** 展示每个 Pack,并通过顶部的范围筛选器在账户、团队之间切换。
点击页面右上角的 **创建**,弹出「创建知识库」对话框。Knowledge Pack 本身没有可编辑的名称——它是按目标(账户或团队)的单例资源,弹窗里只需选择 **范围**:账户或某个团队。创建团队级 Pack 时,您必须是目标团队成员;账户级创建仅限账户 Owner 或管理员。每个目标只能拥有一个 Pack。已有 Pack 的账户或团队仍会出现在下拉列表中,并标记为「已有知识库」;选择后主按钮变为 **打开知识库**,点击即可直接进入该 Pack,不会重复创建。选择没有 Pack 的范围后,点击 **新建** 完成创建;提交前控制台会再次检查,若该范围刚被其他人创建为 Pack,则改为打开已有 Pack。控制台用范围(账户 / 团队名)作为该 Pack 的显示标识。
点击列表中的某一行打开检视器。左侧是文件树,右侧是行内编辑器。点击 **新建文件** 输入文件名(如 `runbook.md`),或用 **上传** 导入本地文件;Markdown 文件支持 **预览** 与 **源码** 两种视图。编辑后点击 **保存**。
左侧 **用量** 条实时显示当前占用 / 5 MB 额度。临近上限时颜色变红,提示您清理或拆分文件。
用列表中的开关 **启用 / 禁用** 整个 Pack——禁用后文件保留,但不再加载到 AI SRE 会话。**删除** 会移除该 Pack 及其下全部文件。
**文件夹上传**:上传对话框中的 **选择文件夹上传** 按钮可以一次导入整个本地文件夹。目录结构会被保留——文件以「顶层文件夹名 / 子路径」作为知识库内的文件路径入库(例如所选文件夹下的 `runbooks/api-5xx.md` 会以 `<文件夹名>/runbooks/api-5xx.md` 落库)。导入前按与单文件上传相同的规则逐文件过滤:必须是 UTF-8 文本、单文件不超过 1 MiB、且加上知识库现有用量后不超过 5 MB 配额;`node_modules` 目录与以 `.` 开头的文件 / 目录会被静默忽略。上传过程中显示进度(「正在上传 N/M 个文件…」),被跳过的文件会在对话框中列出清单,逐条给出文件名与原因(非 UTF-8 文本 / 超过每文件 1 MiB 限制 / 超出知识库 5MB 配额 / 上传失败)。
**文档提炼入库**:知识文件只接受纯文本内容(见上表)。如果上传 `.pdf`、`.docx`、`.xlsx`、`.pptx`、`.html`、`.htm` 这类无法直接入库的文档,控制台会提示该格式无法被 AI 直接使用,并提供 **转到对话分析** 入口。点击后系统会新开一个 AI SRE 会话,把该文档作为附件带入;Agent 阅读文档后将其提炼为 Markdown 知识文件,经您确认后再保存进当前知识库。旧版 Office 二进制格式(`.doc`、`.xls`、`.ppt`)不在转换范围内,会被当作二进制文件直接拒绝——请先另存为 `.docx` / `.xlsx` / `.pptx` 再上传。
**引用一致性检查**:保存文件时,如果其中的 `@引用` 指向一个 Pack 内不存在的文件,会给出非阻断的「引用未解析」警告(不影响保存)。删除一个仍被其它文件引用的文件时,会先提示「仍被引用」冲突,您可以选择 **强制删除**。
Agent 也能在会话中自然语言地维护知识库——例如「补一篇 runbook」「更新 services.md」「记录这个故障模式」。它会直接对当前会话所属作用域执行读取、编辑、保存,无需您离开对话。结构化的初始化(onboarding)则由专门的引导流程完成,而非行内编辑器。
## Agent 如何使用知识
***
知识不是一次性全量加载,而是**目录先行、按需展开**:
会话启动时,系统会把当前作用域的 `DUTY.md` 加载进会话(`DUTY.md` 存在时不附独立文件列表)。绑定了团队的会话会同时加载账户级与该团队的 `DUTY.md`;未绑定团队的会话只加载账户级。若某个作用域有知识文件但尚未创建 `DUTY.md`,系统会改为附上一份生成的文件索引,并要求 Agent 在实质工作前先阅读其中的相关文件。
Agent 阅读 `DUTY.md` 后,根据当前故障决定展开哪些 `@引用`,再读取对应的知识文件取得具体内容。
需要跨团队排障时,Agent 读取另一个团队的知识,系统会把该团队的整套知识(`DUTY.md`、运行手册)连同其 Skill、MCP 一并挂载进当前会话,且在本次会话中持久保留。同一个团队在一次会话里至多挂载一次。
跨团队加载只在 Agent**显式读取**某个团队的知识时触发,不会被模糊的文件遍历误触发。挂载一次后,该团队的知识、Skill 与 MCP 在本次会话内一直可用。
若知识库未能成功加载进当前会话,消息列表上方会出现一条警告横幅:「知识库加载失败 — 本次会话中 AI-SRE 可能无法访问 DUTY.md 与 runbook」,并附带 **重试** 按钮,点击后会重新尝试加载。重试成功前,Agent 在该会话中可能无法读取 DUTY.md 与运行手册。
## 作用域与可见性
***
每个 Knowledge Pack 都有一个作用域:账户级(账户内全局可见)或团队级(仅对该团队成员可见)。
| 维度 | 账户级 | 团队级 |
| ----- | ---------------- | --------------------- |
| 可见范围 | 账户内所有 Agent / 会话 | 仅该团队的会话与成员 |
| 编辑权限 | 账户 Owner 或账户管理员 | 该团队成员,或账户 Owner / 管理员 |
| 会话中加载 | 所有会话 | 仅绑定该团队的会话 |
| 运行时可读 | 全账户 | 全账户(读取即挂载) |
**编辑权限**:账户 Owner 或账户管理员可编辑任意 Knowledge Pack;团队成员可编辑本团队的团队级 Pack;不存在「创建者额外保留权限」的规则。控制台会把你无权编辑的行置灰,并禁用其开关与操作按钮。
**创建与改归属**:创建新的团队级 Pack 时,您必须是目标团队成员;账户级创建仅限账户 Owner 或管理员。编辑已有 Pack 时,账户 Owner 或管理员可以把它移动到任意团队,用于恢复空团队或离职成员留下的资源;普通成员只能移动到自己所属的团队。把已有 Pack 提升为账户级(**设为共享**)与账户级创建同门槛:仅限账户 Owner 或管理员操作,普通成员即使属于该 Pack 所在团队也不能自助提升。
**运行时可见性**:会话开始时,只加载**账户级**资源加上**当前会话绑定团队**的资源。绑定来源是显式指定的团队,或作战室(war room)故障对应的团队。其它团队的知识在会话进行中、当 Agent 读取该团队 `DUTY.md` 时才按需挂载。
账户是运行时唯一的安全边界;团队是「编辑 / 所有权」标签,**不是**「运行时可读」边界。也就是说,账户内任意会话都能读取并挂载本账户其它团队的知识——这是跨团队联合排障的基础。如果某份知识对账户内其它团队也敏感,请评估是否适合纳入知识库。
这套两级作用域模型对账户内所有资源(Skill、MCP、Agent、运行环境)一致适用。
## 最佳实践
***
`DUTY.md` 只放链接列表与一句话导引,所有实质内容下沉到被 `@引用` 的兄弟文件。这样目录精简、可读,Agent 也能只展开当前故障相关的分支,避免无关内容占用上下文。
每篇运行手册聚焦一类故障或一个服务(如 `runbooks/api-5xx.md`、`runbooks/db-pool.md`),用清晰的路径做语义索引。支持子目录组织文件,可按服务或主题分组(如 `runbooks/`、`configs/`)。
服务清单、集群拓扑、阈值配置等结构化信息适合用 `.yaml` / `.json` 承载(如 `services.md`、`cluster.yaml`),让 Agent 既能阅读也能直接解析。脚本片段可用 `.sh`。
新增或重命名文件后,同步更新 `DUTY.md` 与相关文件里的 `@引用`。保存时的「引用未解析」警告与删除时的「仍被引用」提示,能帮您及时发现断链。
账户级 Pack 放跨团队通用的约定(命名规范、通用排障方法、平台访问方式);团队级 Pack 放该团队专属的服务清单、值班手册与上下游。绑定团队的会话会同时拿到两者。
排障过程中沉淀出的新处置经验,可以直接让 Agent「补一篇 runbook」或「记录这个故障模式」,它会对当前作用域读取→编辑→保存,把经验回写进知识库,形成持续积累的闭环。
## 相关页面
***
把可复用的诊断流程封装为 Skill,与知识库共享同一套作用域。
通过 MCP 接入外部系统,让 Agent 调用您的工具与数据。
了解会话如何绑定团队,以及知识在会话中如何被读取与挂载。
# MCP(外部工具连接)
Source: https://docs.flashduty.com/zh/ai-sre/mcp
通过 Model Context Protocol(MCP),让 AI SRE Agent 接入外部工具与数据源——如 GitHub、Slack、Kubernetes、可观测平台等。在控制台中配置 MCP 服务器、认证方式与作用域,Agent 即可在会话中按需调用其工具。
**公测功能**:AI SRE 已全量开放公测,无需申请,登录控制台即可直接使用,公测期间免费。功能与界面可能继续调整。
## 概述
***
**MCP**(Model Context Protocol)让 AI SRE Agent 接入外部工具与数据源。每台 **MCP 服务器**是一个对外暴露一组工具(函数)的标准化端点,例如查询 GitHub Issue、向 Slack 发消息、读取 Kubernetes 资源、检索可观测平台指标等。
在控制台里配置好 MCP 服务器并启用后,Agent 会在排障故障时**自主判断**何时需要外部能力,并直接调用对应工具,无需您手工搬运数据。
本页讲的是 **AI SRE 控制台里的「MCP」**——也就是**Agent 去调用的第三方 MCP 服务器**(您把外部工具接进来给 Agent 用)。
这与开发者文档里的 [Flashduty MCP Server](/zh/developer/mcp-server) 是**两回事**:后者是 **Flashduty 自家对外暴露的 MCP 服务**,供您把 **Flashduty 的能力接入到第三方 AI 客户端**(如 Claude、Cursor)。一个是「Agent 调外部」,一个是「外部调 Flashduty」,方向相反,不要混淆。
## 什么是 MCP
***
**MCP**(Model Context Protocol,模型上下文协议)是一套开放协议,用统一的方式描述「一台服务器对外提供哪些工具、每个工具接收什么参数、返回什么结果」。它就像 AI Agent 世界的「USB 接口」——任何遵循 MCP 的服务器都能被 Agent 即插即用地发现和调用,无需为每个外部系统单独写适配代码。
在 AI SRE 中,MCP 的作用是把 Agent 的能力从「内置工具」扩展到「任意外部系统」:
* 您在控制台添加一台 MCP 服务器(声明它的端点、传输方式与认证)。
* 会话开始时,已启用且在当前作用域可见的服务器即对 Agent 可见、可调用。
* Agent 在需要时即可发现该服务器提供的工具并直接调用。
**MCP 与 Skill 的区别**:MCP 提供**外部工具的接入能力**,Skill 提供**如何编排这些工具完成一类任务的方法论**。Skill 可以在 `SKILL.md` 中以 `mcp:服务名/工具名` 的形式声明它需要哪台 MCP 服务器的哪个工具。详见 [Skill](/zh/ai-sre/skills)。
## 从市场安装 MCP 服务器
***
进入 **插件 → MCP** 页面,点击 **浏览 Marketplace** 打开 **MCP 市场**,可以浏览 Flashduty 精选的第三方 MCP 服务器模板。
在 MCP 列表页点击 **浏览 Marketplace**,弹出市场对话框,以卡片网格展示所有可用的 MCP 服务器模板。每张卡片展示 MCP 服务器名称、作者、简介与标签。
点击任意 MCP 服务器卡片打开详情页,可查看完整描述、传输方式、认证模式、是否需要 BYOC Runner、供应商、连接参数说明与官方文档链接。已安装的 MCP 服务器卡片以齿轮图标标识,点击可直接跳转到该 MCP 服务器的编辑表单。
对尚未安装的 MCP 服务器,点击卡片上的 **安装** 按钮,系统会打开一个新的 AI SRE 会话并注入该 MCP 服务器的模板信息。Agent 随即引导您填写端点地址、完成凭证授权,并调用 `tool_search`(按服务器名探测其工具)验证连通性——整个安装流程**在对话中完成**,而不是一键写库。
Agent 验证连通性通过后,会通过 `/safari/mcp/server/create` 端点将 MCP 服务器写入账户。此后它会出现在 MCP 列表中,并在卡片上以「已安装」状态标识。
市场是**只读浏览**——没有一键安装端点。这是有意为之:MCP 服务器的安装必须经过凭证录入与连通性验证,跳过这两步会在账户里留下永远无法连接的死配置。对话式安装确保每台 MCP 服务器在正式可用前都已通过 Agent 的实际调用验证。
安装完成的 MCP 服务器会在其配置中记录 `source_template_name`,指向来源模板名称,便于日后追溯其原始出处。**市场安装的 MCP 服务器固定为账户级**(`team_id` 为 0),账户内所有成员可用,安装时不提供团队归属选择;同一模板在同一账户内只能安装出一个实例。
需要 **BYOC Runner** 的 MCP 服务器(详情页有 `requires_runner` 标识;`requires_runner` 与传输方式相互独立,当前精选市场均为 HTTP 流式且不需要 Runner)只能在您自己部署了 Runner 的运行环境中使用,云 Sandbox 不支持。安装前请确认您的账户已配置可用的 BYOC Runner,详见 [运行环境(BYOC)](/zh/ai-sre/environments)。
## 添加 MCP 服务器
***
进入 **插件 → MCP** 页面,点击右上角的 **添加服务器**,在弹出的表单中定义一台 MCP 服务器。
### 基础字段
| 字段 | 类型 | 是否必填 | 说明 |
| ---- | ----------------------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 名称 | string | 是 | 服务器名,会作为 Agent 调用时的标识(如 `mcp:sqlite-explorer/query` 中的 `sqlite-explorer`)。须以字母开头,仅含字母、数字、`-`、`_`,长度 1–255。同一账户内**不区分大小写、不可重名**,也不能与内置服务器同名 |
| 传输方式 | 枚举 | 是 | Agent 与服务器通信的方式,见下文「传输方式」 |
| 范围 | 账户 / 团队 | 是 | 该 MCP 服务器的作用域:**账户**(账户内全局可见)或某个**团队**(仅该团队成员可见)。详见下文「作用域」 |
| 执行环境 | 云端环境 / BYOC Runner(可多选) | 否 | 决定该 MCP 服务器在哪些执行环境中可用。可以选择云端环境和一个或多个当前可见的 BYOC Runner;不选择时默认在所有环境可用。它不指定调用路由:MCP 调用仍在当前 AI SRE 会话自身的执行环境中运行。若服务只在某个内网可访问,请只选择能访问它的 Runner。详见 [运行环境(BYOC)](/zh/ai-sre/environments) |
| 描述 | string | 是 | 描述此服务器的功能,便于在列表中识别 |
MCP 服务器还有一个 **AI 描述**:Agent 首次列出某服务器的工具后,系统会根据工具清单自动生成一段服务器能力摘要并展示在列表中。它随工具集变化自动刷新,无需您手工维护。
### 传输方式
| 传输方式 | 适用场景 | 需填字段 |
| ----------- | --------------------------------- | --------------------------------------------------- |
| HTTP 流式(推荐) | 远程 MCP 服务器,通过 HTTP 端点连接 | URL(端点)、可选 Headers(JSON);HTTPS 端点可按需开启「跳过 TLS 证书校验」 |
| SSE(独立、旧版) | 仅支持 Server-Sent Events 的旧版远程服务器 | URL(端点)、可选 Headers(JSON);HTTPS 端点可按需开启「跳过 TLS 证书校验」 |
| stdio(本地命令) | 在 Runner 所在机器上以本地子进程方式启动的 MCP 服务器 | 命令、参数(每行一个)、环境变量(JSON) |
**stdio 仅适用于 BYOC 运行环境**(Runner 部署在您自己的机器上)。云 Sandbox 不能启动本地子进程;如果使用云端运行环境,请改用 **HTTP 流式**或 **SSE**,并确保该 MCP 服务器对 Sandbox 网络可达。运行环境的区别见 [运行环境(BYOC)](/zh/ai-sre/environments)。
连接与调用各有一个默认超时:连接超时默认 10 秒,工具调用超时默认 60 秒。
「跳过 TLS 证书校验」只在远端 HTTPS MCP 服务器使用自签证书、且网络环境受控时开启。开启后,Agent 运行环境连接该服务器时会跳过证书链和主机名校验;不要用于公网不可信端点。
### 认证
MCP 服务器支持三种**认证模式**,决定凭证如何提供给服务器:
所有用户共用同一组凭证。凭证直接写在服务器配置里——HTTP/SSE 传输写进 **Headers**(JSON)(如 `{ "Authorization": "Bearer xxx" }`),stdio 传输写进**环境变量**(JSON)(如 `{ "API_KEY": "xxx" }`)。适合用账户级服务令牌访问的内部系统。
每个用户在**首次调用**该服务器的工具时单独提供自己的密钥,密钥加密存储在账户级别、按用户隔离。
选择此模式需要填写**密钥 Schema**:
| 字段 | 是否必填 | 说明 |
| --------- | ---- | ------------------------------------------ |
| Header 名称 | 是 | 凭证注入到 MCP 请求的哪个 HTTP header(如 `X-Api-Key`) |
| 占位符 | 否 | 输入框占位提示(如 `sk-...`) |
| 帮助链接 | 否 | 指向「如何获取该密钥」的文档链接 |
适合每个工程师使用各自 API Key 的第三方 SaaS(如个人 GitHub Token)。
用户通过 **OAuth 2.1** 流程各自授权;首次调用该服务器的工具时自动弹出授权窗口,授权服务器的发现(discovery)与动态客户端注册(DCR)按需进行,令牌按用户存储并在临近过期时自动刷新。适合支持 OAuth 的服务。
对于「每用户密钥」与「每用户 OAuth」,缺失凭证时 Agent 的工具调用会暂停,并向当前用户弹出凭证录入 / 授权界面;补齐后继续。共享模式下不会向用户索取凭证。
### MCP 服务器授权(设置页)
「每用户密钥」与「每用户 OAuth」的凭证是**按用户**隔离的,因此除了上面那条「对话中按需弹出」的路径,您也可以**在设置页里主动管理**自己对某台 MCP 服务器的授权——两条路径写入的是**同一份**按用户凭证。
**列表里的授权状态**:MCP 列表为每台 MCP 服务器显示一个**当前查看者**视角的授权状态角标;文案随认证模式而异——「每用户密钥」保存后系统从不校验其有效性,因此刻意不用「已连接」这个措辞:
* **每用户 OAuth**:**● 已连接**(已保存有效凭证)/ **○ 未连接**(尚未提供凭证)。
* **每用户密钥**:**● 已保存**(已保存密钥)/ **○ 未填写**(尚未提供密钥)。
* 两种模式通用:**⚠ 已过期**(凭证已过期,OAuth 令牌到期,需重新授权)。
共享模式的 MCP 服务器不涉及按用户授权,此处显示为「—」。对需要个人凭证的服务器,从列表的授权入口打开**凭证**对话框;它只管理您自己的凭证,不会修改服务器的端点、认证模式或作用域配置。
**凭证对话框里的授权操作**:对话框会根据其认证模式与您当前的凭证状态给出操作:
* **每用户 OAuth**:先选择**执行环境**,再点击 **去授权**(未连接时)/ **重新授权**(已连接或已过期时)。可选择云端 Sandbox 或在线的 BYOC Runner,不能选择「自动」;OAuth 的发现、动态客户端注册、令牌交换和后续刷新都从所选环境发起。每次打开时会优先预选上次成功授权且仍在线的环境,否则预选绑定且在线的 Runner,最后回退到云端 Sandbox。OAuth 服务只能从内网访问时,请选择能访问它的 BYOC Runner。浏览器随后会弹出授权窗口(经 `/safari/credentials/oauth/initiate` 发起,返回授权链接后在弹窗中打开)。
* **每用户密钥**:点击 **填密钥**(未连接时)/ **更新密钥**(已连接时),弹出密钥录入弹窗,提交到 `/safari/credentials/secret`。
* **撤销**:已有凭证时可点击 **撤销**(经 `/safari/credentials/revoke`)删除自己保存的凭证,状态回到「未连接」。
OAuth 授权通过一个浏览器**中转页** `/oauth-callback` 完成:授权服务器回调到 fc-safari,后端再 302 跳到该中转页,中转页用 `postMessage` 把结果回传给发起授权的窗口(设置页或对话页),随后自动关闭。整个过程无需手动复制粘贴令牌。
## 管理与检视
***
MCP 列表以表格展示每台服务器的**名称**(含 AI 描述)、**范围**(账户或团队名)、**传输方式**、**启用**开关与**操作**列——列表只包含您在账户中添加的 MCP 服务器;内置 Flashduty MCP 服务器由运行时自动注入,不出现在此列表中,详见下文「检视」小节。顶部的范围筛选条(ScopeBar)可在「全部 / 账户 / 团队」之间切换查看;筛选条右侧的搜索框支持按名称、描述、传输方式、URL 等关键词过滤列表。
用列表里的开关切换。只有**已启用**的服务器才会对 Agent 可见;禁用后 Agent 看不到、也无法调用它。
点击编辑按钮(或直接点击行)打开表单,可修改名称、传输方式、描述、端点 / 命令、认证模式与作用域。无编辑权限时表单以**只读**模式打开,并提示原因。
将 MCP 服务器从当前范围移除。**依赖它的 Agent 将无法再访问其工具**,正在使用它的活跃会话会随之失败。此操作有确认提示。
### 检视:查看某台服务器暴露的工具
一台 MCP 服务器暴露哪些工具,是在**会话中**由 Agent 按需发现的,而不是在控制台静态展示——因为同一台 MCP 服务器在不同运行环境(Runner)下可达性与工具集可能不同,连接状态与工具数量是「按运行环境」而非「全局」的属性。
想确认某台 MCP 服务器在某个运行环境下实际暴露了哪些工具,最直接的方式是在**对话**里让 Agent 列出该服务器的工具,它会把工具清单与每个工具的用法列出来。详见 [对话](/zh/ai-sre/sessions)。
Agent 读取 Flashduty 故障、告警等数据的能力是**内置**的:**Flashduty MCP 服务器**在每个会话启动时由运行时直接注入给 Agent,不经过本页的 MCP 服务器列表接口——它不会出现在上方的服务器列表中,也无需(也无法)在此手动配置、启用或查看。该能力由平台维护,随账户默认可用。
## 作用域
***
MCP 与其他资源(Skill、知识库、Agent、运行环境)共用同一套**两级作用域**模型,分为账户级与团队级:
| 作用域 | 可见性 |
| --- | --------- |
| 账户级 | 账户内所有成员可见 |
| 团队级 | 仅该团队成员可见 |
**编辑权限**:账户所有者或账户管理员可编辑任意 MCP 服务器;团队成员可编辑**本团队**的团队级 MCP 服务器;没有「创建者保留权限」这一例外。无编辑权限时,列表对应行的开关与操作显示为**只读**。
**创建与改归属**:创建新的团队级 MCP 服务器时,您必须是目标团队成员;账户级创建仅限账户所有者或管理员。**从市场安装是例外**:安装固定为账户级,账户内任何成员都可以安装,不需要所有者或管理员权限。编辑已有 MCP 服务器时,账户所有者或管理员可以把它移动到任意团队,用于恢复空团队或离职成员留下的资源;普通成员只能移动到自己所属的团队。但**市场安装的 MCP 服务器不可改归属到团队**——编辑表单中其作用域固定显示为账户;极少量早期遗留的团队级市场行仍可把作用域改回账户(提升为共享),反向则不允许。**该提升操作与账户级创建同门槛,仅限账户 Owner 或管理员**:普通成员即使属于该服务器所在团队也不能自助操作,被拒绝时会提示「请管理员把它设为共享」。
**运行时可见性**:会话开始时,只会向 Agent 提供**账户级** MCP 服务器,以及**当前会话所绑定团队**的服务器。当 Agent 在排障中读取另一个团队的知识后,该团队的 MCP 服务器与 Skill 才会被按需挂载进当前会话。**账户是运行时唯一的安全边界,团队只是归属与编辑的标记。**
## 相关页面
***
Skill 在 SKILL.md 中以 `mcp:服务名/工具名` 调用 MCP 提供的工具。
Agent 与 MCP 共用同一套认证模式与作用域模型。
stdio MCP 服务器需运行在 BYOC Runner 上;了解云 Sandbox 与自托管运行环境的区别。
在会话中观察 Agent 如何检视并调用 MCP 工具。
方向相反的能力:把 Flashduty 接入第三方 AI 客户端的官方 MCP 服务。
# 记忆
Source: https://docs.flashduty.com/zh/ai-sre/memory
AI SRE 从历次对话里自动提炼您的系统信息与偏好,跨会话记住,减少重复背景介绍。
**公测功能**:AI SRE 已全量开放公测,无需申请,登录控制台即可直接使用,公测期间免费。功能与界面可能继续调整。
## 概述
***
AI SRE 每次新会话都是一次新的排障过程。如果每次都要重新告诉 Agent 您的时区、偏好的报告格式、某个服务归谁负责、上次为什么放弃了某个方案,排障效率无从谈起。记忆(Memory)让 Agent 把这些信息从对话里自动提炼出来,存成结构化的记忆条目,在后续会话中重新用上。
记忆和[知识库](/zh/ai-sre/knowledge)是两回事。知识库是您主动维护的长期资料:一份 `DUTY.md` 加运行手册、服务清单等文件,内容由您或 Agent 在对话中编辑写入,结构由您掌控。记忆不需要您维护,它是 Agent 从历次对话中自动沉淀出的一条条独立事实、偏好、步骤或教训,粒度比知识库细得多,不是整段对话的摘要。
## 记忆类型
***
记忆分四种类型,各自有推荐作用域和默认留存期:
| 类型 | 说明 | 推荐作用域 | 默认留存期 |
| -------------- | ------------------------ | -------- | ----- |
| preference(偏好) | 您的个人习惯,比如时区、报告格式、沟通风格 | personal | 180 天 |
| procedure(步骤) | 某类故障的处置步骤,或团队约定的操作顺序 | team | 90 天 |
| fact(事实) | 系统拓扑、服务归属、配置细节等客观信息 | team | 120 天 |
| lesson(教训) | 一次排障中总结出的经验,比如某个方案为什么行不通 | team | 120 天 |
表格里的作用域是推荐值,不是强制绑定。一条记忆最终落在 personal 还是 team,取决于写入时所处的会话:绑定了团队的会话写入 team 作用域,未绑定团队的会话写入您的 personal 作用域。
## 记忆如何产生
***
记忆有两条产生路径:
* **显式**:您在对话中明确要求 Agent 记住某件事时,它会调用记忆工具直接写入一条记忆。
* **自动**:每个回合结束后,会话进入抽取队列,系统在空闲时于后台异步提炼记忆,不需要您额外操作。目前自动抽取主要产生 procedure 类型的记忆,其余三种类型更多来自您的显式要求。
两条路径最终都经过同一个专用的结构化抽取模型处理。系统内部把记忆分成两层:原始抽取存档只写不改,用于留痕;真正提供给 Agent 使用的是从存档整理出的记忆条目,包含名称、摘要、正文、引用来源等字段。记忆抽取目前只对 AI SRE 与 Support 两个应用生效。
## Agent 如何使用记忆
***
记忆不是每一轮对话都实时查询,而是按快照使用:
会话初始化时,以及之后发生上下文压缩时,系统各检索一次相关记忆,把结果冻结成一份快照存进会话状态。
此后的每一轮对话,只把快照里的记忆卡片注入进来。卡片只有名称和摘要,不含正文。
Agent 需要某条记忆的完整内容时,会自己再调用记忆工具去读取或搜索对应条目。
## 作用域与隔离
***
记忆只有 personal(个人)与 team(团队)两种作用域,没有账户级记忆,跨账号读取会被直接拒绝。
| 维度 | personal(个人) | team(团队) |
| ----- | ------------ | ------------------------- |
| 归属 | 记忆所属的那个人 | 记忆所属的那个团队 |
| 读取条件 | 记忆所属的本人 | 当前会话绑定该团队,或调用者本人是该团队的真实成员 |
| 豁免 | 不适用 | owner、admin 都没有豁免 |
| 跨团队读取 | 不适用 | 不存在这样的路径 |
这套隔离规则与 AI SRE 其它资源的权限模型一致:team 作用域不因为您是账户 owner 或 admin 而自动放开,必须是该团队的真实成员。
## 留存与过期
***
每条记忆有 `renewed_at`(最近续期时间)与 `ttl_days`(留存天数),过期时间 `expires_at = renewed_at + ttl_days`。到期后先软删除,随后进入硬清理。记忆被引用时会更新使用次数与最近使用时间。系统不对记忆条数设上限。
## 当前限制
***
控制台目前没有管理记忆的入口。您看不到自己的记忆列表,也无法在页面上编辑或删除某条记忆。唯一的交互方式是在对话里直接让 Agent 记住、修改或忘记某件事,比如说「记住我习惯用 UTC+8 时区」或「忘掉刚才那条偏好」。
记忆抽取的可靠性改进在 2026 年 7 月 20 日才合并上线,运行时间还不长。如果您发现 Agent 该记住的事情跳过了保存、又没有说明原因,欢迎反馈给我们。
## 相关页面
***
了解知识库和记忆的区别:知识库由您主动维护,记忆从对话中自动沉淀。
了解会话如何绑定团队,以及团队作用域的记忆如何跟随会话。
# AI SRE 产品概述
Source: https://docs.flashduty.com/zh/ai-sre/overview
Flashduty 推出的自治 SRE Agent 平台,通过对话让 AI 自主排障、调查故障、沉淀与复用运维知识,并与 Flashduty 故障响应体系及 IM 协作深度联动
**公测功能**:AI SRE 已全量开放公测,无需申请,登录控制台即可直接使用,公测期间免费。功能与界面可能继续调整。
## 什么是 AI SRE
***
AI SRE 是 Flashduty 推出的自治 SRE Agent 平台。您通过对话向 AI 下达指令,由它自主调查故障、排查根因、调用工具执行诊断,并把每次排障中沉淀的运维知识固化下来供后续复用。
它不是一个只会问答的聊天机器人,而是一个**能动手的排障工作者**:会自己规划步骤、读写文件、查询监控与日志、执行命令、调用外部工具(MCP),并在需要时把子任务委派出去,最终给出有调查过程支撑的结论。
AI SRE 与 Flashduty 的故障响应体系深度联动:当 Flashduty 产生故障(incident)或开启作战室协作时,可直接触发一个 AI SRE 会话,让 Agent 带着故障上下文进入排查现场——既可以在控制台里对话,也可以**直接在你的 IM 群(Slack / 飞书 / 钉钉 / 企业微信)里 @ 它**。
用自然语言描述问题,Agent 自主规划、调用工具、给出调查过程与结论,无需您逐条编排脚本。
从故障或作战室一键拉起会话,Agent 携带故障上下文进入排查,沉淀的知识反哺下一次响应。
## 典型场景
***
AI SRE 不止是控制台里的一个对话框——它围绕「故障从触发到复盘」的完整生命周期,覆盖多个协作入口:
在控制台的对话工作区里主动提问:某个服务为何异常、一条告警的根因、一次变更的影响范围。Agent 流式输出规划、工具调用与中间发现,最终给出结论。
无需切换工具——在 Slack、飞书、钉钉、企业微信的群聊或私聊里 **@ AI SRE** 即可发起或续接一次排查,它在**线程内**回答,团队成员全程可见。详见 [IM 集成](/zh/ai-sre/im)。
为故障开启 IM 作战室时,AI SRE **自动跑一轮初步诊断**并把结论回贴到作战室——人还没开始排查,第一手分析就已经在群里了。
用 [`/insight`](/zh/ai-sre/insight) 复盘最近 30 天的会话,量化你把时间花在了哪里、哪些 runbook 缺失、哪些上下文被反复粘贴,输出可复制的改进建议。
## 公测说明
***
AI SRE 已全量开放公测,无需申请,登录控制台即可使用。
公测期间 AI SRE 不单独收费。正式商用前,Flashduty 会提前提供计费信息。
生产变更、重启、回滚和外部通知,最终都由您确认后才会执行。
## 核心能力
***
AI SRE 围绕"对话排障 + 知识沉淀 + 自主执行"构建了一套完整能力,每一项都可在控制台中配置和管理。
以会话为单位与 Agent 协作。会话按顺序处理你的每条消息,支持流式输出、随时取消、长对话自动压缩上下文,以及从故障一键拉起。
在 Slack / 飞书 / 钉钉 / 企业微信中 @ Agent 发起或续接排查,并在故障作战室里自动给出初步诊断。
可被 Agent 调用的 Skill 包,封装可复用的排障流程。范围可设为账户或团队,启用后在会话中按需加载。
以 DUTY.md 为入口、按 @-引用索引的知识包,承载服务清单、runbook、值班路径等长期上下文,按账户/团队分层加载。
通过 Model Context Protocol 接入外部工具与数据源。MCP 服务器不预连接,Agent 在调用时按需建连、执行、断连。
通过标准 A2A 协议把任务委派给外部远端 Agent;AI SRE 自身也对外暴露 Agent Card,供外部客户端反向调用。
Agent 的执行面:默认使用 Flashduty 托管的云端沙箱;也可在自己机器上部署常驻 Runner,让排障进入您的内网。
通过 /insight 复盘最近 30 天的 AI SRE 会话,输出量化概览、工作叙述与可复制的运维改进建议(只读,不自动落地)。
让 AI SRE 按 cron 周期或经 API 触发地执行隐藏会话,自动产出巡检、洞察或复盘结果。
授权外部应用(目前为 GitHub),让 AI SRE 直接进入你的代码仓库工作:理解代码、调查 PR 与提交、按需开 PR 或提 Issue。
## 控制台导航
***
进入 AI SRE 后,顶部导航按以下四个区域组织(菜单名与控制台一致):
| 区域 | 菜单名 | 作用 |
| ---- | ---------------- | ---------------------------------------------------------------------------------------------------------------- |
| 对话 | 对话(Chat) | 与 Agent 协作排障的主工作区。左侧为会话列表(支持搜索、筛选、置顶、归档),右侧为对话与调查过程。 |
| 插件 | 插件(Plugins) | 管理 Agent 可调用的扩展资源,下分四个子标签:**Apps**(已授权的外部应用,如 GitHub)、**Skill**(Skill 包)、**Agents**(A2A 远端 Agent)、**MCP**(外部工具)。 |
| 知识库 | 知识库(Knowledges) | 管理 Knowledge Pack。每个目标最多一个:账户级(对所有 Agent 可见)+ 各团队级(仅在该团队会话中加载)。 |
| 运行环境 | 环境(Environments) | 管理自托管 Runner。常驻进程负责执行 Agent 的工具、Skill 与 MCP 调用;无可用项时会话回退到云端沙箱。 |
| 产物 | 产物(Artifacts) | 查看和管理 Agent 通过 present\_files 工具发布到制品库的文件与报告:支持搜索、按个人 / 团队筛选;每个制品可复制链接、下载、重命名或删除(重命名与删除需编辑权限)。 |
各区域的可见性由您在该账户下的访问权限决定:没有对应权限的菜单或子标签不会在导航中展示。
## 快速开始
***
从登录控制台到跑完第一次排障,详细步骤见 [快速开始](/zh/ai-sre/quickstart)。
## 下一步
***
了解会话、流式输出、取消与上下文压缩,以及如何从故障拉起排查。
在 Slack / 飞书 / 钉钉 / 企业微信里 @ Agent 排障,并了解作战室自动诊断。
使用 /insight 复盘近 30 天会话,发现重复上下文、缺失 runbook 等运维摩擦。
# 15 分钟完成第一次 AI SRE 排障
Source: https://docs.flashduty.com/zh/ai-sre/quickstart
从一个真实故障开始,完成第一次有上下文、有证据、可继续追问的 AI SRE 调查;随后按需建立团队知识并连接真实数据源。
**公测功能**:AI SRE 已全量开放公测,无需申请,登录控制台即可直接使用,公测期间免费。功能与界面可能继续调整。
## 必要概念(30 秒)
***
上手前只需要知道这四件事:
| 概念 | 是什么 |
| ---- | --------------------------------------------------------------------------- |
| 会话 | 你和 Agent 的一次协作,控制台或 IM 里都能开 → [控制台](/zh/ai-sre/sessions) |
| @ 引用 | 把故障现场带进对话的方式,输入 `@` 搜索并插入故障 → [控制台](/zh/ai-sre/sessions) |
| 知识库 | Agent 对你系统的长期记忆,越完整定位越准 → [管理知识](/zh/ai-sre/knowledge) |
| 运行环境 | Agent 动手的地方——云端 Sandbox 或你内网的 BYOC Runner → [运行环境](/zh/ai-sre/environments) |
## 三个入口(从哪儿开始)
***
AI SRE 没有唯一入口,从你现在所在的场景开始就好:
### 控制台对话(Chat)
适合主动排查一个问题、深入追问、沉淀知识。进入 **AI SRE → 对话 → 新建对话**;输入框下方有场景卡,点击即可填入现成提示词;输入 `@` 可引用故障。→ 详见[控制台](/zh/ai-sre/sessions)
### 自动化(Automations)
适合不需要人守着的周期性 / 触发式任务——定时巡检、周报洞察、告警治理。进入 **AI SRE → 自动化**,可从内置模板一键创建(如告警噪音分析、事故响应复盘、每周值班洞察),也可以从零开始自定义任务提示词。它在后台跑一个隐藏会话,结果记录进运行历史,随时可以打开查看完整的调查过程。→ 详见[自动化](/zh/ai-sre/automations)
### IM(@ 召唤 + 作战室自动诊断)
故障发生的现场。在已接入机器人的 Slack / 飞书 / 钉钉 / 企业微信群里 **@ AI SRE** 即可发起或续接排查,它在线程内作答;为故障开启作战室时,AI SRE 会自动跑一轮初步诊断并把结论回贴到作战室。→ 详见[IM 平台](/zh/ai-sre/im)
## 第一次排障(约 5 分钟)
***
前提条件:账户内至少有一条故障记录。AI SRE 已全量开放公测,无需申请。
如果你现在手头没有故障,可以先跳到下面的「之后:把它建设成你的 SRE」。
进入 **AI SRE → 对话**,点击左侧边栏的 **新建对话**。
在输入框里输入 `@`,会弹出故障搜索列表,选中你要排查的那条故障——它会作为一枚引用胶囊插入到输入框里。也可以直接点输入框下方的场景卡 **排查一个故障**:它会把一段现成的提示词填进输入框,你可以在发送前用 `@` 补上具体的故障引用。
发送类似这样的一句话:
```
分析这个故障。先列调查计划,再给出每条结论的证据,不要执行生产变更。
```
Agent 会流式给出它的调查计划、工具调用与中间发现,最后给出带证据支撑的结论。
**完成标志**:你收到一份包含调查计划、工具调用记录和结论的回复,并且可以针对结论继续追问。
**如果卡住,检查这些**:
* 输入 `@` 没搜到目标故障——确认这条故障确实存在于当前账户,名称或编号没有拼错;
* 长时间没有响应或停在"运行环境初始化"——多半是云端 Sandbox 或 Runner 正在启动,稍等片刻;持续无响应见[运行环境](/zh/ai-sre/environments)的故障排查;
* 只给了结论、没给调查计划——直接追问"先给我一份调查计划,再逐条给证据",Agent 会补上;
* 看不到 **AI SRE** 入口——入口按角色权限展示,请联系账户管理员确认你的角色具备 AI SRE 相关权限。
**下一步**:想了解流式输出、取消、Fork、上下文压缩等控制台细节,见[控制台](/zh/ai-sre/sessions)。
## 之后:把它建设成你的 SRE(按需)
***
跑完第一次排障只是起点。AI SRE 排查得准不准,取决于它对你系统的了解程度、以及能连到多少真实数据——这两件事都可以按需慢慢建设,不必一次做完。
### 建一份团队知识库
Agent 每次排障都从零猜「这是什么服务」「谁负责」「以前是怎么处理的」,效率就上不去。在会话里输入 `/init`,Agent 会用访谈的方式带你梳理服务清单、runbook、值班路径等知识,逐条确认后写入知识库,后续会话自动加载。完整访谈流程见[初始化(/init)](/zh/ai-sre/init),知识库结构与最佳实践见[管理知识](/zh/ai-sre/knowledge)。
### 接入真实数据源
默认情况下 Agent 只能看到 Flashduty 自身的数据。要让它查到你系统里的真实信息——日志、指标、代码仓库、内网数据库,需要接入 MCP 服务器或部署 BYOC Runner。公网可达的服务(如可观测平台、GitHub)从 MCP 市场一键安装并授权即可;VPC、内网数据库或本地命令,则需要在能访问目标资源的机器上部署 Runner。见 [MCP(外部工具)](/zh/ai-sre/mcp) 与[运行环境](/zh/ai-sre/environments)。
## 下一步
***
了解 AI SRE 的定位、能力全景与控制台导航。
会话的新建与管理、流式输出、Fork、上下文压缩。
在 IM 群里 @ Agent 排障,了解作战室自动诊断。
云端 Sandbox 与 BYOC Runner 的区别、部署与权限配置。
# Sandbox
Source: https://docs.flashduty.com/zh/ai-sre/sandbox
云端沙箱是 Flashduty 托管的临时执行环境,开箱即用、无需安装。没有当前成员可用的在线自托管 Runner 时,AI SRE 会话默认在云端沙箱里执行;也可在会话中手动指定使用它。
**公测功能**:AI SRE 已全量开放公测,无需申请,登录控制台即可直接使用,公测期间免费。功能与界面可能继续调整。
## 概述
***
**云端沙箱**(Sandbox)是由 Flashduty 托管的**临时执行环境**——一个开箱即用的隔离容器。AI SRE Agent 的工具调用(执行命令、读写文件、运行 Skill、连接 MCP)都可以在其中完成,您**无需安装或维护任何东西**。
它是 AI SRE 的**默认回退环境**:当没有当前成员可用的在线自托管 Runner([BYOC Runner](/zh/ai-sre/environments#byoc-runner))时,会话会自动在云端沙箱里执行;您也可以在会话里**手动指定**使用它。
无需部署任何进程或填写凭据。新账户、临时排查、演示场景都能直接开始对话,由系统分配一个干净的沙箱。
会话空闲时沙箱自动暂停以释放资源;下次发送消息时自动唤醒,继续在同一个工作目录里执行。
## 什么时候用云端沙箱
***
云端沙箱适合**不依赖您内网的排查**,以及快速上手:
* **快速上手 / 演示**:还没有部署 Runner,想先体验 AI SRE 的排障能力;
* **公网可达的诊断**:排查只需要访问 Flashduty 自身数据(故障、告警、变更)或受信任的公网服务;
* **一次性、轻量的任务**:不希望为一次排查去准备一台常驻机器。
云端沙箱**触达不到您的内网**:它的出网被限制在一组受信任的公网域名内,无法访问您 VPC、专线或内网后的数据库、API、跳板机等资源。当排查需要直连这些目标时,请改用自托管的 [BYOC Runner](/zh/ai-sre/environments#byoc-runner)——把执行位置放到能直连内网的机器上。
## 在会话中使用
***
聊天输入框底部的**环境选择器**决定本次会话在哪里执行,与云端沙箱相关的有两个选项:
| 选项 | 行为 |
| ------------- | ------------------------------------------ |
| **自动** | 新会话默认值。优先使用当前成员可用的在线 Runner,否则**回退到云端沙箱**。 |
| **云端沙箱 · 默认** | 强制使用云端沙箱,忽略所有自托管 Runner。 |
环境选择对一条会话是**一次性锁定**的:会话首次发送消息时确定的执行环境会被记录,后续轮次始终沿用,不会因事后切换选择器而改变。要更换执行环境,请新建一条会话。详见 [BYOC · 在会话中选择环境](/zh/ai-sre/environments#在会话中选择环境)。
## 云端沙箱 vs. 自托管 Runner
***
| 维度 | 云端沙箱(Sandbox) | 自托管 Runner([BYOC Runner](/zh/ai-sre/environments#byoc-runner)) |
| ----- | ------------- | -------------------------------------------------------------- |
| 部署 | 无需安装,系统托管 | 在您自己的机器上部署常驻进程 |
| 内网可达性 | ❌ 仅受信任公网域名 | ✅ 可直连您的 VPC / 内网 / 专线 |
| 数据驻留 | 在托管环境内 | 留在您自己的网络边界内 |
| 生命周期 | 临时、空闲自动暂停 | 常驻,由您掌控 |
| 适用场景 | 快速上手、公网诊断 | 触达真实生产环境的深度排查 |
两者并不互斥:日常可以让会话走 **自动**,没有 Runner 时自然回退到云端沙箱;需要触达内网时,连接一个 [BYOC Runner](/zh/ai-sre/environments#byoc-runner) 即可让会话进入您的真实环境。
## 相关页面
***
在自己的机器上部署常驻 Runner,让排查直连您的内网。
在会话中查看本次绑定的执行环境与状态。
MCP 连接在 Agent 运行时于所选环境内建立。
Skill 在所选执行环境中运行。
# 控制台
Source: https://docs.flashduty.com/zh/ai-sre/sessions
AI SRE 会话承载您与 Agent 的一次完整对话,包含消息、流式响应、工具调用与产物;本文介绍会话的新建与管理、分享、消息发送、产物预览、会话 Fork、上下文压缩、团队绑定与会话数据导出。
**公测功能**:AI SRE 已全量开放公测,无需申请,登录控制台即可直接使用,公测期间免费。功能与界面可能继续调整。
## 概述
***
会话(Session)是您与 AI SRE 的一次完整对话。它承载您发送的每一条消息、Agent 的流式回复、过程中的工具调用,以及 Agent 产出的产物(Artifacts,例如代码、报告、图表或 Skill 压缩包)。
每个会话相互独立,拥有自己的上下文、绑定的团队与运行环境。您在左侧边栏切换会话,在中间的对话区收发消息、查看回复与产物。
会话之间彼此隔离:上下文、绑定团队、运行环境互不影响。切换会话不会中断正在运行的回合——AI SRE 会持续把进展写入会话,您返回时可继续看到流式输出。
## 新建与管理会话
***
左侧边栏是会话的统一入口。点击 **新对话** 即可开启一个全新会话;列表按最近活动倒序排列,初始显示最近的若干条,更多历史通过 **显示更多** 逐步展开。
在空白的 AI SRE 新会话中,输入框上方会显示四张场景建议卡片:**排查一个故障**、**用自然语言查数据**、**治理告警噪音**和**定时自动巡检**。点击卡片只会把预置提示填入输入框,不会立即发送;你可以修改后再按 Enter。
### 搜索与筛选
顶部搜索框按会话名称过滤;无结果时显示 **未找到匹配对话**。
点击列表右上角的 **筛选** 图标打开筛选面板,按下列维度组合过滤;当存在非默认筛选时,筛选按钮上会出现一个小圆点提示。
筛选面板支持的维度:
| 维度 | 可选值 | 说明 |
| ---- | ----------------------- | ---------------------------------------------------------------------------------- |
| 范围 | 全部 / 个人 / 团队 | 选择 **团队** 后可在 **我的团队 / 指定团队** 之间切换,默认 **我的团队**;只有切到 **指定团队** 才会展开内联列表,可搜索并多选你所属的团队 |
| 状态 | 活跃 / 归档 / 全部 | 默认仅显示 **活跃** 会话;切到 **归档** 查看已归档会话 |
| 最近活动 | 全部 / 24 小时 / 7 天 / 30 天 | 按会话最近一次活动时间收窄结果 |
面板底部提供 **重置**(恢复默认筛选)与 **完成**(关闭面板)。
### 会话可见性与操作权限
会话以账户为硬边界,跨账户永远不可访问。在同一账户内,个人会话和团队会话的读取、继续对话与管理权限不同:
| 会话类型 | 可读取 / 继续对话 | 可重命名、归档、删除或关联故障 |
| ----------- | --------------- | --------------------------- |
| 个人会话(未绑定团队) | 仅创建者本人 | 仅创建者本人 |
| 团队会话(绑定团队) | 同账户内拿到会话 ID 的成员 | 会话创建者、账户 Owner / 管理员、或该团队成员 |
置顶是个人偏好,不会修改会话本身;只要您有权读取这条会话,就可以为自己置顶或取消置顶。账户 Owner / 管理员可以管理团队会话,但不能读取或管理其他成员的个人会话。
### 分享会话
聊天页头部提供分享入口,仅当您对当前会话有管理权限时显示。点击 **复制分享链接** 按钮即可开启分享并把链接复制到剪贴板(提示「分享链接已复制」);链接在当前会话地址上附加 `share_token`,令牌位于 URL 片段(`#` 之后)中。分享链接是**稳定链接**:分享保持开启期间,重复复制得到的是同一条链接。
| 事项 | 说明 |
| -------- | ----------------------------------------------------------------------------------------------------------------- |
| 谁能分享 | 对会话有管理权限的成员——个人会话的创建者,或团队会话的创建者 / 账户 Owner / 管理员 / 团队成员 |
| 谁能打开 | 持有链接、且登录了**同一账户**的成员;链接不跨账户,也不支持匿名访问 |
| 持链接者看到什么 | 会话以**只读**模式打开,对话区提示「这是一个只读分享会话」:可查看完整上下文(消息、工具调用、产物),也可以点开 Subagent 派发卡片查看子会话的执行详情(同样只读);但输入框被只读提示替换,不能继续对话或修改原会话 |
| 如何继续排查 | 持链接者可点击 **Fork 为新会话**,把会话派生为自己的新会话后继续处理 |
| 如何撤销 | 分享开启后头部出现 **取消分享** 按钮,点击后链接立即失效(提示「分享已取消」);之后重新开启分享会生成新链接,旧链接不会恢复可用 |
分享主要改变**个人会话**的可见性:团队会话本来就允许同账户成员凭会话 ID 读取(见上表),而个人会话默认只有创建者可见,分享链接是同账户其他成员打开它的唯一方式。
隐身(incognito)会话不支持分享。
Subagent / A2A 子会话本身也不能单独开启分享——分享只能在**根会话**上开启。但当你分享了根会话后,持链接者在只读视图里点开 Subagent 派发卡片时,可以一并只读查看对应的子会话执行详情;子会话是纯查看的,不提供 **Fork 为新会话**。撤销根会话的分享后,子会话的访问同时失效。
### 单条会话操作
将鼠标悬停在会话行上,会显示置顶与归档操作;置顶的会话在名称左侧常驻一个图钉标记。
| 操作 | 入口 | 说明 |
| ----------- | ----------- | ------------------------------ |
| 置顶对话 / 取消置顶 | 行内悬停的图钉按钮 | 置顶会话排在列表前列 |
| 归档对话 / 取消归档 | 行内悬停的归档按钮 | 归档后默认从活跃列表隐藏,可在筛选中切到 **归档** 找回 |
| 重命名 | 对话标题处点击直接编辑 | 回车或失焦提交,Esc 取消;名称最长 60 字 |
新会话无需手动命名:第一回合结束后,系统会根据会话内容自动生成标题(`POST /safari/session/generate-name`);在生成完成前,会先用你的第一条消息派生一个临时标题占位,避免侧边栏长时间停在「未命名」。你随时可以**重命名**来覆盖自动生成的标题(标题最长 60 字)。
在会话行上停留片刻,会弹出工具提示,显示完整会话名、所属团队与精确时间——便于在名称被截断时确认这是不是您要找的会话。
### 列表状态指示
每行右侧用一个互斥标记表达当前状态:
| 标记 | 含义 |
| --------- | ------------------------------------ |
| 旋转的圆圈 | 该会话的 Agent 正在运行(有回合在进行中) |
| 蓝色小圆点(未读) | Agent 产出了您尚未查看的新内容 |
| 相对时间 | 以上都没有时,显示最近活动的相对时间(如 `5m`、`3h`、`3d`) |
打开会话即会清除该会话的未读小圆点。
## 发送消息与流式响应
***
在底部输入框输入消息后回车发送。输入框支持 Markdown,并支持以斜杠命令(输入 `/` 调出命令菜单)触发内置 Skill 与命令。
### 附件与上下文引用
点击输入框左下角的加号按钮选择文件,或直接粘贴图片。支持图片、PDF、文本 / Markdown / CSV / HTML,以及 Office 文档(Word / Excel / PowerPoint),单个文件最大 **20MB**。HTML 文件按纯文本读取,并在沙箱中渲染,不会执行其中的脚本。单条消息最多上传 **9 个文件**,且全部附件总大小不超过 **50MB**;文件数与总量上限都会在选择附件时由前端立即校验并分别给出提示——此时附件只是本地暂存(以待发胶囊展示),发送消息时才统一实际上传。截图可直接在对话中粘贴。
未在上面列出的扩展名(如 `.go`、`.py`、`.yaml` 等代码与配置文件),只要文件全文是合法的 UTF-8 文本,也会按纯文本接收;空文件除外,仍会被拒绝。
除单个文件外,还可以**整个文件夹上传**:点击加号菜单中的 **上传文件夹** 选择本地文件夹,或直接把文件夹拖进输入区。文件夹按以下规则处理:
* **文件数上限**:单个文件夹最多包含 **50 个文件**;超过上限时整个文件夹会被拒绝(提示「该文件夹超过 50 个文件上限,请选择更小的文件夹」),而不是只保留前 50 个。`node_modules` 目录与以 `.` 开头的文件 / 目录会被静默忽略,不计入文件数。
* **逐文件校验**:文件夹内的每个文件仍按单文件规则校验(单文件 20MB、附件总量 50MB、类型校验)。不满足的文件会被跳过,选择文件夹后输入区会显示「已跳过 N 个文件」清单,逐条列出文件名与跳过原因(超过 20MB / 超出附件总量 50MB / 非文本文件 / 不支持的文件类型)。
* **附件计数**:整个文件夹在一条消息里只算 **1 个附件**,同样计入单条消息 9 个附件的上限。
* **目录结构保留**:文件夹内文件的相对路径(含顶层文件夹名)会被完整保留并 staging 进沙箱。Agent 看到的是一份按路径排序的文件清单(信封形式,含文件数与总大小),而不是把文件内容内联进上下文;它通过沙箱内的 read / bash / grep 等工具按需读取具体文件。
**大文件的内联截断**:附件以解析出的文本形式内联进 Agent 上下文。解析文本超过 **64KB** 时,只内联开头 **32KB**(在有效的 UTF-8 边界截断),并在附件末尾附上完整文件在沙箱中的路径提示(形如 `~/.flashduty/attachments/...`)——Agent 需要完整内容时,会用沙箱内的 read / bash 等工具按该路径读取原文件,不会丢失内容。此外,超过 **3MB** 的 PDF 不再以原生形式直传模型,而是回退为文本抽取,同样受上述截断规则约束。
从故障、告警、监控规则、监控对象或服务拓扑等页面进入 AI SRE 时,相关对象会作为**引用胶囊**自动嵌入输入框——它是一枚内联的小标签,标明所引用对象的类型——故障、告警事件、告警、监控规则、主机、监控对象、服务拓扑或告警分析——并随消息一起发送给 Agent,让它直接基于该对象开始分析。点击胶囊可在新标签页打开对应对象;点击胶囊上的关闭按钮即可在发送前移除引用。一条消息可携带多个引用。除了从相关页面自动携带引用外,也可以在任意会话的输入框里直接输入 `@` 触发故障搜索下拉(支持关键词模糊匹配与近期故障列表),选中后插入与自动携带相同的引用胶囊——这是一个随时可用的独立引用入口。
会话启动时会按绑定团队自动加载对应的知识库与 Skill;详见下文 知识库 与 Skill 。
### 实时流式输出
发送后,Agent 的回复实时流式返回——文本逐字显示,工具调用与思考过程也会即时呈现。
发送瞬间,前端会乐观地把回合标记为「运行中」;约 300ms 后由后端的运行状态确认接管,因此即便您切换页面再回来,运行状态也不会丢失。
回合运行期间,**发送按钮会变为停止按钮**。点击停止会立即中断当前回合:界面随即反馈,被中断的回合会带上「已中断」标记,刷新后依然可见。
### 运行中继续输入(排队)
回合运行期间输入框依然可用:您可以继续输入并发送,消息会进入队列,在当前回合结束后依次执行。排队消息以一张可折叠的卡片展示在输入框上方,标题显示排队条数(如「3 条排队」);队列中的消息可逐条编辑或移除,超过一条时卡片右上角还提供 **全部清空** 一键清空整个队列。
### 运行环境初始化
会话首次运行时,对话流中会出现一张 **运行环境初始化** 卡片,分步展示运行环境(沙箱)的就绪过程:**建立云端容器 → 启动运行时**;若云端模板本身带有启动脚本,新建或重建时还会追加第三个阶段 **运行 setup 脚本**(恢复已有沙箱时不会重跑该脚本)。各阶段串行推进,每次只显示当前正在进行的一步;全部完成后卡片折叠为一行结果,按本次是新建、恢复还是重建分别显示:
| 模式 | 折叠后的提示 | 含义 |
| -- | ------ | ----------------- |
| 新建 | 已初始化会话 | 首次为会话创建全新的云端容器 |
| 恢复 | 已恢复会话 | 复用此前的沙箱,文件保持不变 |
| 重建 | 已重建会话 | 原沙箱已被回收,已创建一个新的容器 |
当上一个沙箱因空闲被回收时,卡片会给出警示:**原沙箱因闲置 N 分钟被回收 — 已保存的文件被重置**。这意味着此前写入沙箱文件系统的内容已不复存在。请将需要长期留存的产出**保存为 Artifact 或沉淀到知识库**,而不要依赖沙箱内的临时文件。
若初始化过程中出现错误,卡片会转为 **初始化失败** 的错误态,点击可展开查看各阶段的历史与具体错误信息。此时通常需要重试新建会话,或联系 Flashduty 支持。
## 工具调用与产物
***
Agent 在回合中调用的工具(读写文件、查询监控、执行命令、调用 MCP 工具等)以内联可折叠的形式呈现在对话流中,点击即可展开查看输入与输出,默认折叠以保持对话整洁。
### 任务计划(Todo List)
执行多步骤任务时,Agent 会在对话流中放置一枚可点击的进度徽标(形如「第 X / N 步」,带环形进度指示),点击展开为任务计划清单:每一步都带状态图标(未开始 / 执行中 / 已完成 / 已取消)与优先级标签(高 / 中 / 低)。当 Agent 结束回合但某一步仍处于「执行中」时,该步会呈现为「已暂停」,提示您需要发送新消息才能推进,而不是仍在后台运行。
### Agent 提问
排障过程中,Agent 可能需要您澄清信息,这时会在对话流中插入一张交互式提问卡片:单选(点击选项即自动进入下一题)、多选(勾选后需点击 **确认** / **下一步** 才继续)或自定义文本输入(回车提交)。卡片右上角的 **✕** 按钮可跳过整卡提问(必答题不显示该按钮);多题批次时会额外显示「第 i / N 题」的翻页控件,可用键盘 ←→ 或点击翻页在题目间切换,切换回已答过的题目会保留之前的选择。支持键盘操作:↑↓ 移动选项、Enter 确认、Esc 跳过。
### 需要授权时
当工具或 MCP 调用因缺少凭证或未完成 OAuth 授权而受阻时,对话流中会内联出现一张 **授权〈资源名〉以继续** 卡片,按授权方式分两种:
* **密钥类**:点击卡片按钮弹出输入框,粘贴 API Key / Token 并保存后任务会自动继续;若配置了帮助链接,卡片会附带「如何获取密钥?」。
* **OAuth 类**:点击 **去授权** 在弹出的授权窗口中完成第三方授权;授权完成后卡片按钮变为 **继续任务**,需要您手动点击才会真正恢复被阻塞的工具调用。
OAuth 授权链接有过期时间;过期后卡片会提示「授权链接已过期,请重新触发任务」,需要重新发起一次任务才能拿到新的授权链接。
### 子任务(Subagent)
Agent 委派子任务时,对话中会出现一枚可点击的芯片:展示子任务名称与当前意图,进行中显示旋转图标与独立的停止按钮,结束后显示工具调用数 / Token 用量 / 耗时,失败时显示失败原因;若子任务卡在等待授权,芯片上还会给出可点击的授权链接。点击芯片会在右侧打开一个与主对话并排的子会话面板——主对话区域随之收窄,而不是被弹窗遮挡;面板可展开为占满主区域的全屏视图,也可以收起回并排布局。子任务仍在运行时,面板与芯片上都提供独立的停止按钮,只中断该子任务,不影响主会话。
### Artifacts 预览
Agent 产出的文件会以产物形式提供预览。点击产物即在右侧打开预览面板,按类型渲染:
| 类型 | 预览方式 |
| ------------------- | ---------------------------------------- |
| 代码(多语言) | 语法高亮 + 行号 |
| Markdown | 默认渲染视图,可切换 **源码** |
| HTML | 默认渲染视图(iframe 沙箱),可切换 **源码** |
| 图片 | 直接显示;加载失败时给出可重试提示 |
| PDF | 浏览器内置查看器渲染 |
| Skill 压缩包(`.skill`) | 左侧文件树 + 右侧内容,可整包下载,并可一键 **保存 Skill** 到账户 |
预览面板提供 **复制**、**下载** 与 **关闭** 操作。
报告类产物(如运营洞察报告)可生成包含 Mermaid 图、图表的 HTML,并在渲染视图中直接查看。运营洞察相关能力见 运营洞察报告 。
所有已发布的产物也可在左侧导航 **产物** 页统一查看与管理(列表、搜索、按个人 / 团队筛选、重命名、下载与删除),详见 产物 。
### 消息操作
将鼠标悬停在消息上会显示操作按钮:
| 操作 | 适用 | 说明 |
| ---- | --------------- | ------------------------------------------------------------- |
| 复制 | 用户消息 / 产物 | 复制消息或文件内容到剪贴板 |
| 重试 | 用户消息 | 以该消息重新发起回合 |
| 编辑 | 用户消息 | 将该消息内容回填到输入框重新编辑;若当前有回合正在运行会先被中断,编辑期间无法添加附件,发送按钮文案变为 **发送回滚** |
| Fork | 已完成回合的 Agent 回复 | 从这条回复所在的完成回合派生一个新会话,继续尝试另一条排查路径 |
编辑一条历史消息本质上是一次 **回滚(rewind)** 操作:提交后会从该消息处重新生成对话,这条消息之后的内容会被替换,请确认后再提交。
### Fork 会话
当一个回合已经完整结束后,Agent 回复右侧会出现 **Fork** 按钮。点击后会弹出「Fork 新对话」对话框:对话框会以源会话的范围和运行环境作为预填建议,但 Fork 必须明确选择目标范围与运行环境。你可以选择个人或可访问的团队,并从 **自动**、云端 Sandbox 或在线的 BYOC Runner 中选择运行环境;点击 **确认** 后才会从该回复所在的回合派生一个新会话,并自动打开。
Fork 适合在同一段排查上下文上尝试另一条路线:新会话保留截至所选回合为止的对话与工具调用记录,但不会在后端继承源会话的环境绑定。环境选项会按目标范围过滤;如果你不属于源团队,系统会改为个人范围;如果源环境已删除、离线、从未连接,或不属于目标范围,系统会改为 **自动**。后续回合不会带入新会话。新会话会写入一条「由 Chat 派生」分隔线,点击分隔线可回到原会话的来源位置。
只能从**已经完成**的主会话回合 Fork。源会话仍在运行、所选回合尚未完成,或目标是 Subagent 子会话时,系统会拒绝 Fork。
如果被 Fork 的这段对话里派发过 Subagent 或 A2A 任务,那些派发卡片会连同各自的子会话一起复制到新会话下,点开仍能查看执行详情,不会指向你无权访问的原始任务。但**复制过来的派发一律显示为「已中断」**——即使原会话里那次派发早已正常完成也一样:新会话没有承接该派发的执行者,无法继续或重放它。需要重跑时,在新会话里重新发起一次派发即可。
Fork 会话会清理只属于运行中的临时状态,例如当前回合缓存、待挂载状态、未持久化的前端状态与本轮计数;已经持久化在历史中的消息、工具调用、可复用的压缩状态会保留,团队与环境绑定则按您在派生对话框中的选择写入新会话。Fork 后的新会话拥有独立的上下文,之后的消息、压缩与运行结果都不会写回原会话。
### 会话反馈
聊天页头部提供一对会话级反馈按钮 **有帮助** / **没帮助**(拇指向上 / 向下),用于对整个会话的质量打分。
点击 **没帮助** 会弹出一张反馈卡片,可勾选预置原因并补充说明:
| 预置原因 | 说明 |
| ------- | ------------- |
| 诊断/根因错误 | 诊断结论或定位的根因不正确 |
| 没定位到问题 | 没有找到真正的根因 |
| 处置建议不可用 | 给出的处置建议无法落地 |
| 答非所问 | 回复偏离了你的问题 |
卡片底部还有一个自由文本框,可补充具体问题(可选)。提交后反馈通过 `POST /safari/feedback/create` 持久化;重新打开该会话时,之前的评分会自动回填到头部按钮上。
## 上下文压缩
***
随着对话变长,会话上下文会逼近模型的上下文窗口上限。AI SRE 会自动压缩较早的对话历史——把它总结为一段摘要并保留最近内容,从而在不丢失关键信息的前提下腾出上下文空间。
压缩有四种触发方式:
| 方式 | 触发时机 |
| --------- | ------------------------------------------ |
| 自动(回合开始前) | 回合开始前,上下文占用超过阈值时自动压缩 |
| 自动(回合进行中) | 回合进行中上下文继续增长并越过阈值时再次压缩 |
| 自动(事件数触发) | 会话事件累计达到约 **500 条**时自动压缩,即使 token 占用仍在阈值以下 |
| 手动 | 您主动通过 `/compact` 命令触发压缩 |
**事件数触发**是兜底机制:当会话由大量短小回合组成时,token 估算可能长期低于阈值,但事件(消息、工具调用等)数量持续增长。事件数达到约 500 条时强制压缩一次,避免历史窗口因逼近模型单次加载上限而冻结。若您观察到 Context 占用百分比远低于阈值时也发生了压缩,即属此情况。
### 您会看到什么
* **压缩进行中**:对话流中出现一行「正在压缩对话上下文…」的状态提示,并显示已用时长与进度,压缩完成后自动消失。
* **压缩完成**:对话保持连贯,无需您介入;最直接的指示是聊天页头部的 **Context** 占用百分比随之下降——它反映当前上下文窗口的利用率,将鼠标悬停可查看具体的 token 用量。
* **无需压缩**:当上下文无需压缩(如对话历史太短、已是压缩态)时,手动触发会给出相应提示,例如「上下文无需压缩」「对话历史太短,无需压缩」。
压缩对您是透明的:您感知到的是一段连续的对话。Agent 在后台保留了被压缩内容的摘要,因此后续回合仍能基于此前的关键结论继续工作。
## 选择运行环境
***
新建会话时,输入区除了团队选择器外还有一个独立的 **运行环境** 选择器,用来决定 Agent 的工具、Skill 与 MCP 调用具体在哪里执行。选择器分三段:
| 选项 | 说明 |
| -------------- | ---------------------------------------------- |
| 自动(默认) | 由后端自动选择一个可用环境;无可用项时回退到云端沙箱 |
| 云端环境 | 使用 Flashduty 托管的云端沙箱(默认模板,或账户 / 团队下已创建的云端环境模板) |
| 指定 BYOC Runner | 从您账户内在线的自托管 Runner 中选择一台,让排障进入您的内网 |
自托管 Runner 会按当前状态展示:离线或从未连接过的 Runner 在列表中会置灰,无法选中;若已选中的 Runner 之后离线,也会阻止发送消息并给出提示。
环境选择在发送第一条消息、创建会话时即固定;如需切换,可参考下文「会话入口类型」中 IM 会话的就地切换能力,或 Fork 出一个新会话。
## 绑定团队
***
新建会话时可以为会话 **绑定团队**。绑定后,会话在启动时会自动加载该团队的知识库、Skill 与 MCP,让 Agent 一开始就具备这个团队的领域上下文与能力。未绑定团队时,会话以账户范围运行。
在新建会话的输入区通过团队选择器挑选要绑定的团队;您上次的选择会被记住,省去每次重复选择。
会话启动即加载「账户范围 + 绑定团队」的知识库 / Skill / MCP 元数据,Agent 随即可用。
当 Agent 需要其它团队的知识时,会按需读取对应团队的知识目录,将该团队的知识与能力作为持久上下文挂载进当前会话——一次挂载在本会话内持续有效。
绑定的团队会随会话保留:重新打开同一会话时,仍是原先绑定的团队;该会话所属团队也会在侧边栏的会话提示中标注。
故障 / 作战室与团队的自动联动仍在演进中。当前您可以为会话显式 **绑定团队**;后续故障场景下的自动绑定能力会持续完善。
资源的团队作用域(账户范围与团队范围、可见性与编辑权限)规则,详见各资源页面的「作用域」一节。
## 会话入口类型(entry\_kind)
***
每个会话在创建时都带有一个 **入口类型(entry\_kind)**,用于标识本次会话由哪个接入面产生。该字段持久化到数据库,并在创建响应中返回。
| 值 | 来源 | 说明 |
| ------------ | ----------------------------- | -------------------------------- |
| `web` | 控制台 | 默认值;未传入或传入未知值时自动归一为 `web` |
| `im` | IM 平台(飞书 / 钉钉 / 企业微信 / Slack) | 由 IM 渠道自动设置;启用会话的**就地切换**能力(见下方) |
| `api` | 外部 API 调用 | 用于程序化集成场景 |
| `automation` | 自动化流程 | 由自动化任务触发的会话 |
通过 `POST /safari/session/create` 创建会话时,可在请求体中传入 `entry_kind`(可选,省略即为 `web`)。`entry_kind` 一经创建不可修改。
`entry_kind=im` 的会话支持**就地切换运行环境与团队范围**——即通过 IM 中的 `/env` 与 `/scope` 命令,在不中断对话的情况下重新绑定 BYOC Runner 或团队。控制台会话(`web`)的环境与团队在创建时固定,不支持就地切换。
## 回复语言
***
每个会话在创建时会确定一个 **回复语言**,Agent 在整个会话期间都用该语言回复,不会中途切换;之后重新打开会话时也沿用该语言。
| 入口类型 | 回复语言来源 |
| ------------------------------------------- | -------------------------------------- |
| 控制台(`web`) | 跟随创建会话时的控制台界面语言;创建后即固定,之后切换界面语言不影响已有会话 |
| IM / API / 自动化(`im` / `api` / `automation`) | 这些入口不携带界面语言信号,默认使用账户的通知语言 |
## 会话数据导出
***
通过 `POST /safari/session/export` 可以将一个会话的全部事件以 **NDJSON**(`application/x-ndjson`)格式流式导出,每行一个 JSON 对象。这一能力适用于审计、归档、离线分析或将会话数据接入外部系统等场景。
### 请求参数
| 字段 | 类型 | 必填 | 说明 |
| ------------------- | ------ | -- | ----------------------------------------- |
| `session_id` | string | 是 | 要导出的会话 ID |
| `include_subagents` | bool | 否 | 为 `true` 时递归包含所有子 Agent 会话的事件流;默认 `false` |
### 响应格式
响应的 `Content-Type` 为 `application/x-ndjson`,**第一行始终**是 `session_meta` 类型的会话元数据信封,后续各行为会话事件。启用 `include_subagents=true` 时,每遇到一条 `subagent_dispatch` 类型的行,其后紧跟该子会话的完整事件流,子会话同样以自己的 `session_meta` 行作为起始。
```
{"type":"session_meta","session_id":"...","app_name":"..."} // 第一行:会话元数据
{"type":"message","..."} // 后续:事件行(类型依内容而异)
{"type":"subagent_dispatch","child_session_id":"..."} // 子 Agent 派发标记
{"type":"session_meta","session_id":"","..."} // 子会话元数据
{"type":"message","..."} // 子会话事件
```
若流式传输已开始后发生错误,服务器**无法**切换回标准 JSON 错误包。此时会在流末尾追加一行 JSON 编码的错误对象,消费方需检测该行以判断流是否完整。
**权限**:导出端点使用与发送消息相同的权限门控(`CanChatSession`),即要求调用方具备该会话的消息收发权限,单纯的只读访问权限不够。个人会话只能由创建者导出;团队会话可由同账户内具备会话访问能力的成员导出。
## 相关页面
***
了解 AI SRE 的定位、能力与适用场景。
基于会话数据生成团队的故障处理与运营洞察。
为会话提供领域知识,按团队加载与跨团队按需挂载。
用斜杠命令调用的可复用 Skill。
通过 MCP 连接外部系统,扩展 Agent 的工具能力。
在 Slack / 飞书 / 钉钉 / 企业微信里 @ Agent 排障,作战室自动诊断。
# Skill
Source: https://docs.flashduty.com/zh/ai-sre/skills
Skill 是可复用的能力包:一段 SKILL.md 说明加上允许使用的工具,供 AI SRE Agent 在对话中按需调用。从市场安装、上传自定义 Skill,或在对话中用 skill-creator 直接创建。
**公测功能**:AI SRE 已全量开放公测,无需申请,登录控制台即可直接使用,公测期间免费。功能与界面可能继续调整。
## 概述
***
Skill 是一个**可复用的能力包**。一个 Skill 由两部分组成:
* 一段 **SKILL.md** 说明文档,告诉 Agent「什么场景下用、怎么用、按什么步骤做」;
* 该 Skill 声明的**允许使用的工具**,以及可选的参考资源文件(脚本、模板、子文档等)。
Skill 被打包成 Skill 归档(`.zip` 或 `.tar.gz`,扩展名 `.zip` / `.skill` / `.tar.gz` / `.tgz`)上传到 AI SRE,`.tar.gz` 在安装时会被规范化为标准 zip。归档的根目录必须包含一个 `SKILL.md` 文件,其余资源文件可放在归档内任意位置,Agent 可在执行时按需读取。
启用后,该 Skill 即在会话中对 Agent 可见、可被调用。Agent 既可以**自主判断**何时调用某个 Skill,您也可以在对话框里用 `/`(如 `/skill-creator`)来**显式触发**它。
显式触发时还可以追加参数:`/ 参数1 参数2`。SKILL.md 正文可以用 `$1`…`$9` 引用按空白拆分的位置参数,用 `$ARGUMENTS` 引用参数串的完整原文;这些占位符会在该轮对话发送前被替换为实际值。
如果只是想在消息里**提到** `/skill-name`(比如问「`\/skill-name` 是做什么的?」)而不想触发它,可以在消息开头加一个反斜杠转义:以 `\/` 开头的消息会被去掉这个反斜杠、按普通文本发送,不会被解析为命令。
Skill 与 MCP 的区别:MCP 提供**外部工具的接入能力**,Skill 提供**如何编排这些工具完成一类任务的方法论**。两者配合使用——Skill 在 SKILL.md 里声明它需要哪些工具,包括内置工具和 `mcp:服务名/工具名` 形式的 MCP 工具。
### SKILL.md 格式
`SKILL.md` 由 YAML frontmatter(元数据)和正文(Agent 可读的说明)两部分组成,以 `---` 分隔:
```markdown theme={null}
---
name: skill-name
description: USE FIRST for ... — 简明说明此 Skill 解决的问题与适用场景
version: "1.0.0"
tags:
- tag1
- tag2
author: author-name
license: MIT
allowed-tools: bash, read, task
---
## Instructions
Skill 正文写在这里:执行步骤、约束、注意事项……
```
frontmatter 字段如下:
| 字段 | 类型 | 是否必填 | 说明 |
| --------------- | --------- | ---- | -------------------------------------------------------------------------------------- |
| `name` | string | 是 | Skill 名,kebab-case 格式(仅小写字母、数字、连字符,如 `my-skill-name`),长度 1–64。会作为 `/` 的触发词 |
| `description` | string | 否 | Skill 描述。这是 Agent 选择 Skill 的核心信号,建议写成「USE FIRST / prefer-over-X」式的祈使句,越精准越容易被正确调用 |
| `version` | string | 否 | 版本号,如 `1.0.0` |
| `tags` | string\[] | 否 | 标签列表 |
| `author` | string | 否 | 作者 |
| `license` | string | 否 | 许可证 |
| `allowed-tools` | string\[] | 否 | 此 Skill 允许使用的工具清单,留空表示不额外限制 |
工具的写法有两种:
* **内置工具**:直接写工具名。可用的内置工具包括 `read`、`write`、`edit`、`bash`、`grep`、`glob`、`skill`、`mcp`、`todo`、`time`、`webfetch`、`web_search` 等。
* **MCP 工具**:写成 `mcp:服务名/工具名`(如 `mcp:my-server/query`)。上传时只校验该 MCP 服务是否存在,具体工具名在会话中加载 MCP 时才会被验证。
AI SRE 运行时内置了几个 Skill,无需安装即可使用。`flashduty` 是其中一个范例:它通过 `fduty` 命令行覆盖整个 Flashduty API,让 Agent 可以排障故障、读取 AI 详情、查询告警、关联变更等。您可以参考它来编写自己的 Skill。另一个内置 Skill 是 `github`,Agent 会从 `` 中自主选用它,让 AI SRE 直接在 GitHub 仓库里工作——探索代码、调查 PR / 提交、按需开 PR 或 Issue;它需要安装 GitHub App(云端)或运行环境主机上的 `gh`(BYOC)。第三个内置 Skill 是 `gitlab`,能力与 `github` 对称:Agent 自主选用它在 GitLab 仓库里探索代码、追溯 MR / Issue、按需开 MR 或 Issue;它需要安装 GitLab App(云端)或运行环境主机上的 `glab`(BYOC)。详见 [Apps](/zh/ai-sre/apps)。
## 从市场安装
***
进入 **插件 → Skill** 页面,点击 **浏览 Marketplace** 打开 Skill**目录**,可以浏览并安装 Flashduty 与 Anthropic 提供的 Skill 模板。
在 Skill 列表页点击 **浏览 Marketplace**,弹出目录对话框,以卡片网格展示所有可用 Skill 模板。
顶部搜索框按名称或描述检索;右上角的**筛选**可只看「已安装」或「未安装」,**排序**支持「已安装优先」或「名称 A–Z」。
在未安装的卡片上点击 **+** 按钮,会弹出「安装 Skill」确认对话框(标题中带模板名称),提示「将安装到账户,账号内所有成员可用」——市场安装的 Skill 固定为**账户级**,不提供归属选择。点击 **安装** 才会真正调用安装接口,把模板内容复制到您的账户,成为一个普通 Skill 行,并标记其来源模板(卡片上以 `v<版本>` 角标标识「来自 Marketplace」)。
已安装的卡片右上角变为齿轮图标,点击进入该 Skill 的检视面板进行管理。
新账户会自动预装一组官方 Marketplace 模板:`browser-automation`(浏览器自动化 CLI,用于操作网站/仪表盘/监控 UI)、`mcp-builder`(指导创建 MCP 服务器)、`monit-agent`(Flashduty Monit 告警的目标侧诊断)、`monit-query`(Monit 数据源查询)与 `skill-creator`(见下文「在对话中创建」)。这些预装 Skill 与手动安装的 Skill 完全一样,可以在下方「管理与检视」中启用/禁用、卸载或更新到最新版本。
**同名冲突**:若账户里已存在同名 Skill,且它**不是**从同一模板安装的(例如您手工上传的自定义 Skill),安装会被拒绝——市场安装不会覆盖或接管这类 Skill,即使选择覆盖更新也一样。此时请先删除该自定义 Skill,再安装同名市场模板。
### 自动更新与手动更新
当市场中的模板发布了更高版本时,对应 Skill 行会出现 **有更新** 标记。是否自动更新取决于该 Skill 是否被本地改动过:
安装后未做任何本地修改的 Skill,会在列表加载时**自动**拉取市场最新版本并覆盖,无需手动操作;更新成功后会有提示。
被本地编辑或重新上传过的 Skill,自动更新会**跳过**,避免覆盖您的改动。它会保留「有更新」标记,需您**手动**点击更新并确认覆盖。
对已改动 Skill 执行更新,会用市场最新版本**覆盖您的本地改动且无法恢复**。界面会弹出「覆盖更新」确认框,请谨慎操作。重新安装市场版本后,本地改动标记会被清除,该 Skill 恢复为纯净状态、重新参与自动更新。
## 自定义 Skill
***
除了从市场安装,您也可以上传自己的 Skill 包。在 Skill 列表页点击 **上传 Skill**,在表单中填写:
| 字段 | 类型 | 是否必填 | 说明 |
| ------ | ------- | ---- | ------------------------------------------------------------------------------------------------ |
| 归属 | 团队 / 账户 | 是 | 选择 Skill 的作用域:**账户**(账户内全局可见)或某个**团队**(仅该团队成员可见)。上传到团队作用域时,您必须是目标团队成员;账户级上传仅限账户所有者或管理员。详见下文「作用域」 |
| Zip 文件 | 文件 | 是 | 包含 `SKILL.md`(必需)及可选资源文件的归档;接受 `.zip` / `.skill` / `.tar.gz` / `.tgz` 归档 |
上传时系统会自动校验:归档是合法 zip、根目录存在 `SKILL.md`、frontmatter 可解析、`name` 符合 kebab-case 命名、声明的工具有效(内置工具存在、MCP 服务存在)。同一账户内**Skill 名不能重复**,重名会被拒绝并提示换名。
Skill 名以外的元数据(描述、版本、标签、作者、工具等)都从 `SKILL.md` 的 frontmatter 解析得到,无需在表单中重复填写。
### 覆盖上传(Replace)
当您要用新版本替换已有 Skill 时,上传端点支持两种覆盖模式,界面会在适当时机弹出「替换」确认对话框:
| 模式 | 触发条件 | 行为 |
| ----------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| **按名称覆盖** | 上传 zip 时携带 `replace=true`,且不指定 `skill_id` | 以新归档的 `SKILL.md` 中 `name` 字段匹配账户内同名 Skill 并覆盖其内容;SkillID 不变,所有对该 Skill 的引用(如 `/` 触发)继续生效 |
| **按 ID 覆盖** | 上传 zip 时携带 `replace=true` 且指定 `skill_id` | 不依赖 zip 内的 `name` 字段,直接以指定 ID 定位并替换对应 Skill;适合在重命名后仍要覆盖原记录的场景 |
两种模式在替换成功后均返回更新后的 Skill 对象;若目标 Skill 不存在,返回 404 错误而非新建。**不携带 `replace` 参数时(默认),重名归档会被直接拒绝**,上传端点不会隐式覆盖已有 Skill。
### 在对话中创建(skill-creator)
除了上传 zip,您还可以**直接在 AI SRE 会话里创建和打磨 Skill**。`skill-creator` 是 Flashduty 在 Marketplace 提供、并默认预置到账户的一个 Skill,专门用来「造 Skill」。在任意会话里用 `/skill-creator` 触发,或直接用自然语言提出需求即可:
* **从零创建**:说「帮我创建一个用于排查 X 的 Skill」,或在一次排障结束后说「把刚才这套流程固化成一个 Skill」。skill-creator 会与您澄清意图、起草 `SKILL.md`、(可选)建立测试用例并据此迭代,满意后一键保存为账户里的 Skill。
* **改写与优化**:在某个 Skill 的检视面板点击 **「在聊天中编辑」**,会以 skill-creator 改写该 Skill;它也能帮您打磨 `description`,提升被正确触发的准确度。
Agent 完成起草后可一键把内容保存为 Skill;与已有 Skill 重名时,保存前会弹出「替换」确认对话框——底层即走按名称覆盖模式(`replace=true`,无 `skill_id`)。
Skill 归档大小有上限:通过对话中 Agent 打包保存的归档上限为 **10 MB**,通过网页表单或会话内呈现文件上传的归档上限为 **100 MB**。
## 管理与检视
***
Skill 列表以表格展示每个 Skill 的**名称**(含来源模板角标与「有更新」标记)、**范围**(账户或团队)、**版本**、**启用**开关与**操作**列。列表上方的工具条提供范围筛选(全部 / 账户 / 团队)与搜索框,搜索按名称、描述或作者中的关键词过滤列表。
用列表或检视面板上的开关切换。只有**已启用**的 Skill 才会对 Agent 可见;禁用后 Agent 看不到、也无法调用它。
点击编辑按钮可更新**描述**与**归属**(作用域)。市场安装的 Skill 归属固定为账户,编辑表单中作用域不可改。如需修改 Skill 内容,请下载 zip、编辑后**重新上传**(这会创建新版本,并把该 Skill 标记为已改动)。
在检视面板选择「替换」,用一个新的 zip 覆盖当前 Skill 内容;SkillID 保持不变,对它的引用(如 `/` 触发)依然有效。
下载完整 zip 包(含 `SKILL.md` 和所有资源文件),便于离线编辑或备份。
将 Skill 从当前范围移除。正在使用它的活跃会话会持续失败,直到重新安装。此操作有确认提示。
### 检视面板
在列表中点击任意一行,打开 Skill**检视面板**:
* **左侧**:Skill 包的文件树(`SKILL.md`、`README.md` 等会优先作为默认预览文件)。
* **右侧**:选中文件的内容预览,顶部显示 Skill 描述。
* **标题区**:Skill 名(短引用形如 `skill-xxxxxx`)、范围标签(账户 / 团队名)、来源模板版本角标(鼠标悬停显示「来自 Marketplace — 模板名 v版本」)、**有更新**标记、作者、`version`、以及完整 SkillID。
* **操作**:在聊天中试用(向新会话注入 `/`)、更新到最新版本、在聊天中编辑、替换、下载、卸载。
Skill 包**过大无法预览**时,检视面板会提示体积并建议改用「下载」查看。
## 作用域
***
Skill 与其他资源(知识库、MCP、Agent、运行环境)共用同一套**两级作用域**模型,分为账户级与团队级:
| 作用域 | 可见性 |
| --- | --------- |
| 账户级 | 账户内所有成员可见 |
| 团队级 | 仅该团队成员可见 |
**编辑权限**:账户所有者或账户管理员可编辑任意 Skill;团队成员可编辑**本团队**的团队级 Skill;没有「创建者保留权限」这一例外。无编辑权限时,列表对应行显示为**只读**。
**创建与改归属**:上传新的团队级 Skill 时,您必须是目标团队成员;账户级上传仅限账户所有者或管理员。**从市场安装是例外**:安装固定为账户级,账户内任何成员都可以安装,不需要所有者或管理员权限,也不能在安装时选择团队。编辑已有 Skill 时,账户所有者或管理员可以把它移动到任意团队,用于恢复空团队或离职成员留下的资源;普通成员只能移动到自己所属的团队。但**市场安装的 Skill 不可改归属到团队**——编辑表单中其作用域固定显示为账户;极少量早期遗留的团队级市场 Skill 可通过检视面板的「设为共享」提升为账户级。**「设为共享」与账户级上传同门槛,仅限账户 Owner 或管理员**:普通成员即使属于该 Skill 所在团队也不能自助提升,操作被拒绝时会提示「请管理员把它设为共享」。
**运行时可见性**:会话开始时,只会加载**账户级**Skill,以及**当前会话所绑定团队**的 Skill。当 Agent 在排障中读取另一个团队的知识后,该团队的 Skill 与 MCP 才会被按需挂载进当前会话。**账户是运行时唯一的安全边界,团队只是归属与编辑的标记。**
对话框 `/` 自动补全下拉只展示**账户级 Skill** 以及**您所属团队**的团队级 Skill,用于保持菜单简洁——这只影响补全菜单里能看到什么,不代表执行权限的边界。若您手动输入一个不在补全列表里的 Skill 命令(例如某个您不属于的团队的团队级 Skill),只要该 Skill 属于同一账户且已启用,仍会被正确解析并执行。
## 相关页面
***
用 DUTY.md 与知识包为 Agent 提供团队上下文与排障经验。
接入外部工具,让 Skill 在 SKILL.md 中以 `mcp:服务名/工具名` 调用它们。
用 Agent 扩展 AI SRE 的协作与分工能力。
在会话中用 `/` 显式触发 Skill,或让 Agent 自主调用。
了解 AI SRE 的整体能力与定位。
# 活跃告警
Source: https://docs.flashduty.com/zh/monitors/alert-rules/active-alerts
查看当前正在触发的所有告警,快速了解系统整体告警状态
活跃告警页面汇总展示当前所有正在触发的告警,帮助您快速了解系统的整体告警状态。您可以按严重程度、标题、标签等维度进行筛选和查看。
活跃告警功能依赖 monit-edge 版本 >= v0.36.0,请确保您已升级至该版本或以上。如尚未安装,请前往[告警引擎管理](https://console.flashcat.cloud/monit/engine/list)页面完成部署。
## 查看活跃告警
**菜单入口**:选择一个文件夹后,切换到「活跃告警」标签页
活跃告警列表以表格形式展示当前正在触发的告警,默认列包括:
| 列名 | 说明 |
| ---------------- | -------------------------------------------- |
| **严重程度** | 告警的严重级别,包括 Critical(严重)、Warning(一般)、Info(轻微) |
| **告警标题** | 告警事件的标题 |
| **Job** | 告警携带的 job 标签值 |
| **Instance** | 告警携带的 instance 标签值 |
| **最后更新** | 该告警最后一次更新的时间 |
| **Hash** | 告警的唯一标识哈希值 |
| **Extra labels** | 告警携带的其他附加标签信息 |
## 筛选与搜索
页面顶部提供筛选条件栏,帮助您快速定位关注的告警:
* **严重程度**:按 Critical、Warning、Info 筛选
* **告警标题**:按告警事件的标题筛选
* **Hash**:按告警的唯一标识哈希值筛选
* **Job**:按 job 标签值筛选
* **Instance**:按 instance 标签值筛选
* **Extra labels**:按其他附加标签筛选
各筛选条件之间为"与"的关系,同时满足所有条件的告警才会被展示。
## 自定义列
点击列表右上角的列配置按钮,您可以:
* **显示/隐藏列**:勾选或取消勾选需要展示的列
* **调整列顺序**:拖拽调整各列的显示顺序
系统会记住您的列显示偏好,下次访问时自动应用。
当您添加标签类型的列时,对应的标签筛选条件也会自动出现在条件栏中,方便您快速过滤。
## 删除告警
如果某些活跃告警已不再需要关注(例如告警规则已调整但旧告警尚未自动恢复),您可以手动删除:
在列表中勾选需要删除的告警,支持多选。
点击批量删除按钮,确认后所选告警将从活跃告警列表中移除。
删除操作仅将告警从活跃告警列表中移除。如果告警条件仍然满足,下次告警引擎执行检查时,该告警会重新出现。
# ClickHouse
Source: https://docs.flashduty.com/zh/monitors/alert-rules/clickhouse
配置 ClickHouse 数据源的告警规则,支持标准 SQL 语法
Monitors 支持使用标准 SQL 语法对 ClickHouse 进行查询,并根据查询结果触发告警。
## 前置说明
| 配置项 | 说明 |
| -------- | ----------------------------------------- |
| **查询语言** | 使用 ClickHouse SQL 语法 |
| **字段处理** | 所有字段名自动转换为小写,配置时请使用小写字母 |
| **类型转换** | 建议使用 `toString()`、`toFloat64()` 等函数转换复杂类型 |
## 1. 阈值判定模式
此模式适用于需要对聚合后的数值进行阈值比对的场景。
### 配置方式
1. **查询语句**:编写 SQL 聚合查询,返回数值列和(可选的)标签列。
* 示例:统计最近 5 分钟内,各服务的错误日志数量。
```sql theme={null}
SELECT
service_name,
count(*) AS error_cnt
FROM app_log
WHERE timestamp > now() - INTERVAL 5 MINUTE AND level = 'error'
GROUP BY service_name
```
2. **字段映射**:
* **值字段**:选择 `error_cnt`,用于阈值判定。
* **标签字段**:选择 `service_name`,用于标识告警对象。明确选择标签字段后,其他非值字段会作为附加信息随告警携带。
* 详细规则请参见[查询结果字段映射](/zh/monitors/alert-rules/query-result-fields)。
3. **阈值条件**:
* 使用 `$A.field_name` 引用数值。
* 示例:`Critical: $A.error_cnt > 50`,`Warning: $A.error_cnt > 10`。
### 工作原理
Monitors 按标签字段区分告警对象,并使用值字段进行阈值判定。标签字段留空时,除值字段外的所有返回字段都会作为标签。
### 恢复逻辑
| 策略 | 说明 |
| ---------- | ----------------------------------- |
| **自动恢复** | 当数值不再满足任何告警阈值时,自动生成恢复事件 |
| **特定恢复条件** | 配置恢复表达式(如 `$A.error_cnt < 5`) |
| **恢复查询** | 独立 SQL 用于恢复判定,支持 `${label_name}` 变量 |
## 2. 数据存在模式
此模式适用于将过滤逻辑直接写在 SQL 中的场景。
### 配置方式
1. **查询语句**:在 SQL 中使用 `HAVING` 子句直接过滤出异常数据。
* 示例:直接查询错误数超过 50 的服务。
```sql theme={null}
SELECT
service_name,
count(*) AS error_cnt
FROM app_log
WHERE timestamp > now() - INTERVAL 5 MINUTE AND level = 'error'
GROUP BY service_name
HAVING count(*) > 50
```
2. **判定规则**:只要 SQL 查询返回了数据,即触发告警。
### 优缺点分析
| 类型 | 说明 |
| ------ | ------------------------------------- |
| **优点** | 利用 ClickHouse 强大的 OLAP 能力进行计算和过滤,性能极佳 |
| **缺点** | 无法区分多级告警 |
### 恢复逻辑
* **数据消失即恢复**:当 SQL 查询结果为空时,判定恢复
* **恢复查询**:支持配置额外的查询语句用于辅助判断恢复状态
## 3. 数据缺失模式
此模式用于监控"预期应该有数据,但实际没有数据"的场景。
### 配置方式
1. **查询语句**:编写一个预期应该持续返回数据的 SQL 查询。
* 示例:查询所有探针的心跳上报。
```sql theme={null}
SELECT probe_id, max(timestamp) as last_seen
FROM probe_heartbeat
WHERE timestamp > now() - INTERVAL 5 MINUTE
GROUP BY probe_id
```
2. **判定规则**:如果某个 `probe_id` 在之前的周期中出现过,但在当前及连续 N 个周期中查不到数据,则触发"数据缺失"告警。
## 4. 最佳实践
ClickHouse 的驱动在处理复杂类型时可能返回引擎无法识别的格式。建议在 SELECT 子句中显式转换:
* `toString(uuid)`
* `toFloat64(avg_duration)`
ClickHouse 对时间分区非常敏感,务必在 `WHERE` 子句中包含时间范围过滤以利用索引:
* `timestamp > now() - INTERVAL 5 MINUTE`
* `timestamp > toDateTime(now()) - 300`
Monitors 会将 ClickHouse 返回的列名统一转为小写。填写标签字段和值字段时,请始终使用小写字母。
# 备注模板
Source: https://docs.flashduty.com/zh/monitors/alert-rules/description-template
配置 Monitors 告警规则备注描述的 Go Template 变量、关联查询结果和 Sprig 函数。
Monitors 告警规则的 **备注描述(Description)** 用于定义告警和恢复事件中的说明文本。你可以使用 Go `text/template` 引用告警标签、查询值、关联查询结果和安全的 Sprig 函数,生成 Text 或 Markdown 格式的描述内容。
本文描述的基础模板变量、Sprig 函数名和标签增强后再渲染 `Description` 的行为需要 monit-edge `v0.42.0` 或以上版本。通过 `$annotations` 读取 `$<查询名称>.<字段名称>` 格式的查询附加信息需要 monit-edge `v0.53.0` 或以上版本;使用该能力前,请先升级告警引擎。
## 工作方式
规则触发或恢复时,monit-edge 会把完整告警事件作为模板根对象,并额外注入一组常用短变量。标签增强执行完成后,模板会基于增强后的事件渲染,结果会写入事件的 `Description` 字段,再继续发送事件。
日常模板建议优先使用 `$labels`、`$values`、`$value`、`$relates`、`$status` 和 `$checkMode`。其他短变量用于高级模板或兼容场景,只有确实需要时再使用。
## Sprig 函数名
monit-edge 会使用 Sprig 标准函数名注册安全的 Sprig 函数。同一个可用函数也会额外注册一份 `sprig_` 前缀形式,方便在命名冲突时使用。
应该这样写:
```gotemplate theme={null}
{{ contains "Unknown column" $msg }}
{{ regexMatch "Unknown column" $msg }}
{{ regexFind "Unknown column '[^']+'" $msg }}
```
也可以使用带前缀的形式:
```gotemplate theme={null}
{{ sprig_contains "Unknown column" $msg }}
{{ sprig_regexMatch "Unknown column" $msg }}
{{ sprig_regexFind "Unknown column '[^']+'" $msg }}
```
如果 Sprig 标准函数名与 monit-edge 自定义函数重名,monit-edge 自定义函数会保留标准函数名,Sprig 函数仍可通过 `sprig_` 前缀调用。
## 内置变量
| 变量 | 类型 | 说明 |
| --------------- | ------------------------- | --------------------------- |
| `$labels` | `map[string]string` | 告警标签,与 `.DataLabels` 相同。 |
| `$values` | `map[string]float64` | 告警计算中使用到的数值,与 `.Values` 相同。 |
| `$value` | `float64` | 主告警值,与 `.Value` 相同。 |
| `$appendLabels` | `map[string]string` | 规则上配置的附加标签。 |
| `$annotations` | `map[string]string` | 规则自定义字段和查询结果携带的附加信息。 |
| `$dsType` | `string` | 数据源类型。 |
| `$dsName` | `string` | 数据源名称。 |
| `$dsAddress` | `string` | 数据源地址,不包含认证信息。 |
| `$checkMode` | `string` | 检测模式。 |
| `$relates` | `map[string][]*ResultRow` | 关联查询结果行。 |
| `$status` | `string` | `firing` 或 `recovered`。 |
| `$severity` | `string` | 告警级别。 |
示例:
```gotemplate theme={null}
{{- if eq $status "firing" }}
规则 {{ .RuleName }} 在 {{ $dsName }} 上触发,当前值:{{ printf "%.2f" $value }}
{{- else }}
规则 {{ .RuleName }} 已恢复。
{{- end }}
```
### 查询结果附加信息
如果主查询明确配置了标签字段,其他非值字段会作为附加信息进入 `$annotations`。查询附加信息始终使用 `$<查询名称>.<字段名称>` 作为 key:
```gotemplate theme={null}
{{ index $annotations "$A.sample_message" }}
{{ index $annotations "$B.sample_message" }}
```
无论只有一个还是多个查询,也无论使用阈值判定、数据存在还是数据缺失模式,写法都相同。`$` 前缀专门用于查询字段,规则中手工配置的自定义字段名称不能以 `$` 开头。字段如何分类,请参见[查询结果字段映射](/zh/monitors/alert-rules/query-result-fields)。
## 根对象字段
根对象字段使用 `.FieldName` 访问。
| 字段 | 类型 | 说明 |
| -------------------- | ------------------------- | ------------------------------------------------------ |
| `.Hash` | `string` | 稳定的事件 hash。同一个事件的告警和恢复使用相同 hash。 |
| `.DataSourceType` | `string` | 数据源类型。 |
| `.DataSourceName` | `string` | 数据源名称。 |
| `.DataSourceAddress` | `string` | 数据源地址,不包含认证信息。 |
| `.RuleName` | `string` | 告警规则名称。 |
| `.RuleID` | `uint64` | 告警规则 ID。 |
| `.Queries` | `[]Query` | 规则查询定义。 |
| `.RelateQueries` | `[]RelateQuery` | 关联查询定义。 |
| `.CheckMode` | `string` | 检测模式。 |
| `.DataLabels` | `map[string]string` | 告警标签。 |
| `.AppendLabels` | `map[string]string` | 规则上配置的附加标签。 |
| `.EnrichLabels` | `map[string]string` | 外部标签增强接口返回的标签。标签增强会先于 `Description` 渲染执行,因此模板可以引用这些标签。 |
| `.Values` | `map[string]float64` | 告警计算中使用到的数值。 |
| `.Annotations` | `map[string]string` | 规则自定义字段和查询结果携带的附加信息。 |
| `.Relates` | `map[string][]*ResultRow` | 关联查询结果行。 |
| `.Status` | `string` | `firing` 或 `recovered`。 |
| `.Severity` | `string` | 告警级别。 |
| `.EvalTime` | `int64` | 本次评估时间,Unix 秒级时间戳。 |
| `.Description` | `string` | 渲染后的描述。该字段在模板执行完成后才设置。 |
| `.DescriptionType` | `string` | 描述类型,例如 `text` 或 `markdown`。 |
| `.Value` | `float64` | 主告警值。 |
| `.TitleRule` | `string` | edge 上配置的标题规则。 |
`.Queries` 中的 `Query` 对象包含 `.Name`、`.Expr`、`.LabelFields`、`.ValueFields` 和 `.Args`。
`.RelateQueries` 中的 `RelateQuery` 对象包含 `.Name`、`.Expr` 和 `.Args`。
## 关联查询结果行
关联查询结果通过 `$relates` 访问。map 的 key 是关联查询名称,例如 `R1`。
| 字段或方法 | 类型 | 说明 |
| ------------------- | ------------------------ | ------------------------------------------- |
| `$row.Fields` | `map[string]interface{}` | 关联查询返回的非数值字段或展示字段。 |
| `$row.Values` | `map[string]float64` | 关联查询返回的数值字段。 |
| `$row.Field "name"` | `interface{}` | 从 `$row.Fields` 读取一个字段。 |
| `$row.Value` | `float64` | 返回 `$row.Values` 中的第一个数值;如果没有数值则返回 `NaN`。 |
| `$row.Value "name"` | `float64` | 从 `$row.Values` 读取一个数值;如果 key 不存在则返回 `NaN`。 |
| `$row.String` | `string` | 返回该行的调试字符串。 |
示例:
```gotemplate theme={null}
{{- range $row := $relates.R1 }}
- 日志:{{ $row.Field "_msg" }}
- 次数:{{ printf "%.0f" ($row.Value "count") }}
{{- end }}
```
## Go Template 内置函数
以下函数由 Go `text/template` 提供。
| 函数 | 说明 | 示例 |
| ---------- | -------------------------- | ------------------------------------------ |
| `and` | 逻辑 AND。结果确定后停止继续求值。 | `{{ if and $a $b }}yes{{ end }}` |
| `or` | 逻辑 OR。结果确定后停止继续求值。 | `{{ if or $a $b }}yes{{ end }}` |
| `not` | 逻辑 NOT。 | `{{ if not $ok }}failed{{ end }}` |
| `eq` | 等于。 | `{{ if eq $status "firing" }}...{{ end }}` |
| `ne` | 不等于。 | `{{ if ne $severity "Info" }}...{{ end }}` |
| `lt` | 小于。 | `{{ if lt $value 10.0 }}...{{ end }}` |
| `le` | 小于等于。 | `{{ if le $value 10.0 }}...{{ end }}` |
| `gt` | 大于。 | `{{ if gt $value 10.0 }}...{{ end }}` |
| `ge` | 大于等于。 | `{{ if ge $value 10.0 }}...{{ end }}` |
| `index` | 从 map、slice 或 array 中读取元素。 | `{{ index $labels "instance" }}` |
| `slice` | 对字符串、slice 或 array 做切片。 | `{{ slice "abcdef" 0 3 }}` |
| `len` | 返回长度。 | `{{ len $relates.R1 }}` |
| `printf` | 使用 `fmt.Sprintf` 语法格式化文本。 | `{{ printf "%.2f" $value }}` |
| `print` | 使用默认格式拼接多个值。 | `{{ print $dsName ":" $status }}` |
| `println` | 类似 `print`,但会追加换行。 | `{{ println $dsName }}` |
| `call` | 调用函数值。Description 中通常很少使用。 | `{{ call .SomeFunc }}` |
| `html` | 按 HTML 规则转义文本。 | `{{ html $text }}` |
| `js` | 按 JavaScript 规则转义文本。 | `{{ js $text }}` |
| `urlquery` | 按 URL query 规则转义文本。 | `{{ urlquery $text }}` |
## monit-edge 自定义函数
以下函数由 monit-edge 注册,使用时不需要前缀。
| 函数 | 说明 | 示例 |
| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| `pathEscape text` | 对 URL path 做转义。 | `{{ pathEscape "a/b c" }}` |
| `queryEscape text` | 对 URL query 做转义。 | `{{ queryEscape "level=error msg" }}` |
| `getvalue values key [format]` | 从 `map[string]float64` 中读取数值并格式化。默认格式是 `%.4f`。如果 key 为空或不存在,会返回 `template_function_error: ...` 文本。 | `{{ getvalue $values "$A" "%.2f" }}` |
| `getfvalue values key` | 从 `map[string]float64` 中读取数值。如果 key 为空或不存在,返回 `NaN`。 | `{{ if gt (getfvalue $values "$A") 10.0 }}high{{ end }}` |
| `trunc count text` | `truncRune` 的别名。按 Unicode 字符截断,不按字节截断。`count` 为负数时从末尾保留字符。 | `{{ trunc 10 $msg }}` |
| `truncRune count text` | 按 Unicode 字符截断。 | `{{ truncRune -8 "abcdef你好" }}` |
| `runeCount text` | 统计 Unicode 字符数。 | `{{ runeCount "你好abc" }}` |
| `args ...` | 构造一个 map,key 为 `arg0`、`arg1` 等。 | `{{ args "a" 1 }}` |
| `reReplaceAll pattern repl text` | 正则替换。参数顺序是 `pattern`、`replacement`、`text`。正则非法时会导致模板渲染失败。 | `{{ reReplaceAll ".*id=([0-9]+).*" "$1" $msg }}` |
| `safeHtml text` | 将文本转换为 `html/template.HTML` 类型。Description 使用 `text/template` 渲染,该函数不会清洗 HTML,也不会改变转义行为。普通 text 或 Markdown 不建议使用。 | `{{ safeHtml "OK " }}` |
| `match pattern text` | 正则匹配,等价于 Go `regexp.MatchString`。正则非法时会导致模板渲染失败。 | `{{ if match "Unknown column" $msg }}...{{ end }}` |
| `toUpper text` | 转成大写。 | `{{ toUpper $severity }}` |
| `toLower text` | 转成小写。 | `{{ toLower $status }}` |
| `stripPort hostPort` | 从 `host:port` 中去掉端口。如果解析失败,返回原始值。 | `{{ stripPort "example.com:9100" }}` |
| `stripDomain hostPort` | 去掉主机名中的域名后缀,并保留端口。IP 地址会原样返回。 | `{{ stripDomain "node01.prod.local:9100" }}` |
| `humanize value` | 使用 SI 单位格式化数字。 | `{{ humanize 12345 }}` |
| `humanize1024 value` | 使用 1024 进制单位格式化数字。 | `{{ humanize1024 1048576 }}` |
| `humanizeDuration seconds` | 将秒数格式化为可读时长。 | `{{ humanizeDuration 3661 }}` |
| `humanizePercentage value` | 将比例格式化为百分比。 | `{{ humanizePercentage 0.1234 }}` |
| `humanizeTimestamp seconds` | 将 Unix 秒级时间戳转为 UTC 时间文本。 | `{{ humanizeTimestamp .EvalTime }}` |
| `toTime seconds` | 将 Unix 秒级时间戳转为 `time.Time`。 | `{{ (toTime .EvalTime).Format "2006-01-02 15:04:05" }}` |
| `nanoTime value [tzOffset]` | 将 Unix 纳秒级时间戳转为 `time.Time`。可选时区偏移单位为小时。 | `{{ (nanoTime $row.Fields.__time__ 8).Format "2006-01-02 15:04:05" }}` |
| `timeFormat value format [tzOffset]` | 格式化 `time.Time`、`*time.Time`、RFC3339 字符串或 RFC3339Nano 字符串。可选时区偏移单位为小时。 | `{{ timeFormat "2026-01-06T11:48:12Z" "2006-01-02 15:04:05" 8 }}` |
| `parseDuration duration` | 解析时长字符串并返回秒数。 | `{{ parseDuration "5m" }}` |
| `add a b` | 数值加法。 | `{{ add 1 2 }}` |
| `sub a b` | 数值减法。 | `{{ sub 10 3 }}` |
| `mul a b` | 数值乘法。 | `{{ mul $value 100 }}` |
| `div a b` | 数值除法。除零会导致模板渲染失败。 | `{{ div $value 1024 }}` |
| `now` | 当前时间,类型为 `time.Time`。 | `{{ now.Format "2006-01-02 15:04:05" }}` |
| `toString value` | 使用 `fmt.Sprint` 将值转为字符串。 | `{{ toString $row.Fields._msg }}` |
## Sprig 函数
monit-edge 会使用 Sprig 标准函数名注册安全的 Sprig 函数,同时也注册 `sprig_`
前缀形式。Sprig 函数来自 [Masterminds/sprig](https://github.com/Masterminds/sprig);
需要查看上游函数行为时,可以参考该仓库文档。
常用示例:
```gotemplate theme={null}
{{ contains "error" $msg }}
{{ regexMatch "Unknown column" $msg }}
{{ regexFind "Unknown column '[^']+'" $msg }}
```
正则使用注意事项:`regexFind` 和 `sprig_regexFind` 返回的是完整匹配文本,不返回捕获组。如果要提取捕获组,请使用 `regexReplaceAll` 或 `sprig_regexReplaceAll`:
```gotemplate theme={null}
{{- $msg := "Unknown column 'community_posts.comment_count' in 'field list'" }}
{{- regexReplaceAll ".*Unknown column '([^']+)'.*" $msg "$1" }}
```
结果是:
```text theme={null}
community_posts.comment_count
```
### 常用 Sprig 函数
| 函数 | 说明 | 示例 |
| ----------------------------------- | ------------------------------------------ | ----------------------------------------------------- |
| `contains substr text` | 判断 `text` 是否包含 `substr`。 | `{{ if contains "Unknown column" $msg }}...{{ end }}` |
| `hasPrefix prefix text` | 判断前缀。 | `{{ hasPrefix "prod-" $name }}` |
| `hasSuffix suffix text` | 判断后缀。 | `{{ hasSuffix ".log" $file }}` |
| `regexMatch pattern text` | 正则匹配。 | `{{ regexMatch "error\|failed" $msg }}` |
| `regexFind pattern text` | 返回第一个完整正则匹配。 | `{{ regexFind "trace_id=[a-z0-9]+" $msg }}` |
| `regexFindAll pattern text n` | 返回最多 `n` 个完整正则匹配。`-1` 表示全部返回。 | `{{ regexFindAll "id=[0-9]+" $msg -1 }}` |
| `regexReplaceAll pattern text repl` | 正则替换。参数顺序是 `pattern`、`text`、`replacement`。 | `{{ regexReplaceAll ".*id=([0-9]+).*" $msg "$1" }}` |
| `trim text` | 去掉首尾空白字符。 | `{{ trim $msg }}` |
| `lower text` | 转小写。 | `{{ lower $severity }}` |
| `upper text` | 转大写。 | `{{ upper $severity }}` |
| `default default value` | 当 `value` 为空时使用默认值。 | `{{ default "unknown" (index $labels "instance") }}` |
| `toJson value` | 将值转为 JSON。 | `{{ toJson $labels }}` |
| `dict ...` | 创建字典。 | `{{ dict "name" $dsName "status" $status }}` |
| `list ...` | 创建列表。 | `{{ list "a" "b" "c" }}` |
同一个函数也可以使用 `sprig_` 前缀调用,例如 `sprig_contains` 和 `sprig_regexReplaceAll`。
### 禁用的 Sprig 函数
为了保证告警描述渲染过程可预测且安全,monit-edge 不会注册会读取进程环境变量、执行 DNS 解析、生成随机输出、创建凭证或证书、加解密数据,或者主动让模板失败的 Sprig 函数。
以下 Sprig 函数的标准形式和 `sprig_` 前缀形式都不可用:
```text theme={null}
env / sprig_env
expandenv / sprig_expandenv
getHostByName / sprig_getHostByName
bcrypt / sprig_bcrypt
htpasswd / sprig_htpasswd
derivePassword / sprig_derivePassword
genPrivateKey / sprig_genPrivateKey
buildCustomCert / sprig_buildCustomCert
genCA / sprig_genCA
genCAWithKey / sprig_genCAWithKey
genSelfSignedCert / sprig_genSelfSignedCert
genSelfSignedCertWithKey / sprig_genSelfSignedCertWithKey
genSignedCert / sprig_genSignedCert
genSignedCertWithKey / sprig_genSignedCertWithKey
encryptAES / sprig_encryptAES
decryptAES / sprig_decryptAES
randBytes / sprig_randBytes
uuidv4 / sprig_uuidv4
randAlphaNum / sprig_randAlphaNum
randAlpha / sprig_randAlpha
randAscii / sprig_randAscii
randNumeric / sprig_randNumeric
randInt / sprig_randInt
shuffle / sprig_shuffle
fail / sprig_fail
```
如果模板使用这些函数,解析阶段会报类似 `function "env" not defined` 或 `function "sprig_env" not defined` 的错误。
## 完整示例:提取 MySQL Unknown Column 字段名
```gotemplate theme={null}
{{- if eq $status "firing" }}
在过去5分钟的时间内,数据库操作出现缺失字段错误 {{ $value | printf "%.0f" }} 次;
{{- range $x := $relates.R1 }}
{{- $msg := printf "%v" ($x.Field "_msg") }}
{{- if contains "Unknown column" $msg }}
{{- $field := regexReplaceAll ".*Unknown column '([^']+)'.*" $msg "$1" }}
- 缺失字段:{{ $field }}
- 查看地址:https://example.com/logs?query={{ queryEscape "Unknown column" }}
{{- end }}
{{- end }}
{{- else }}
数据库缺字段错误已恢复
{{- end }}
```
## 排障
`function "contains" not defined` 表示规则运行在较旧的 monit-edge 版本上,该版本尚未启用 Sprig 标准函数名。请升级 monit-edge;如果该版本支持前缀形式,也可以临时改用 `sprig_contains`。
`function "env" not defined` 或 `function "sprig_env" not defined` 表示模板使用了被禁用的 Sprig 函数。请删除该函数,或改用确定性的模板逻辑。
`regexFind` 或 `sprig_regexFind` 返回 `Unknown column 'x'` 而不是 `x` 是预期行为。提取捕获组请使用 `regexReplaceAll` 或 `sprig_regexReplaceAll`。
# ElasticSearch
Source: https://docs.flashduty.com/zh/monitors/alert-rules/elasticsearch
配置 ElasticSearch 数据源的告警规则,支持 SQL 聚合查询
Monitors 通过 ElasticSearch SQL 功能实现对日志和指标数据的监控,支持灵活的聚合查询与告警判定。
## 核心概念
由于依赖 SQL 特性,仅支持 **ElasticSearch 6.3** 及以上版本。
| 配置项 | 说明 |
| -------- | ----------------------- |
| **查询语言** | 目前仅支持 SQL 语法 |
| **字段处理** | 所有字段名自动转换为小写,配置时请使用小写字母 |
## 1. 阈值判定模式 (Threshold)
此模式适用于需要对聚合后的数值进行阈值比对的场景,例如监控"最近 5 分钟错误日志数量"。
### 配置方式
1. **查询语句**:编写 SQL 聚合查询,返回数值列和(可选的)分组列。
* 示例:统计最近 5 分钟内,各服务的错误日志数量。
```sql theme={null}
SELECT service_name, count(*) AS error_cnt
FROM "app-logs-*"
WHERE "@timestamp" > now() - INTERVAL 5 MINUTES AND log_level = 'ERROR'
GROUP BY service_name
```
2. **字段映射**:
* **标签字段**:选择 `service_name`,用于标识告警对象。明确选择后,其他非值字段会作为附加信息随告警携带。
* **值字段**:选择 `error_cnt`,用于阈值判定。
* 标签字段留空时,除值字段外的所有返回字段都会作为标签。详细规则请参见[查询结果字段映射](/zh/monitors/alert-rules/query-result-fields)。
3. **阈值条件**:
* 使用 `$A.字段名` 引用数值。
* 示例:`Critical: $A.error_cnt > 50`,`Warning: $A.error_cnt > 10`。
* 简写:如果只配置了一个值字段,可以直接使用 `$A`,如 `$A > 50`。
### 工作原理
引擎执行 SQL 查询,获取二维表格数据。根据"标签字段"将数据分组,然后提取"值字段"的数值与阈值表达式进行比对。
标签字段组合唯一标识一个告警对象,查询结果中不能有多行数据具有相同的标签字段值组合。
### 恢复逻辑
| 策略 | 说明 |
| ---------- | ------------------------------------- |
| **自动恢复** | 当数值不再满足任何告警阈值时,自动生成恢复事件 |
| **特定恢复条件** | 配置恢复表达式(如 `$A.error_cnt < 5`),防止告警抖动 |
| **恢复查询** | 编写独立 SQL 用于恢复判定,支持 `${label_name}` 变量 |
告警 SQL 查出了 `network_host="a", interface="b"` 的网卡挂了,恢复 SQL 可以写:
```sql theme={null}
SELECT network_host, interface, status FROM "network-status-*"
WHERE "@timestamp" > now() - INTERVAL 5 MINUTES
AND network_host = '${network_host}'
AND interface = '${interface}'
AND status = 'UP'
```
引擎会将变量替换为实际值后执行查询,如果查到数据,则判定恢复。
## 2. 数据存在模式 (Data Exists)
此模式适用于将过滤逻辑直接写在 SQL 中的场景,或者只需要关注"是否有数据返回"的情况。
### 配置方式
1. **查询语句**:在 SQL 中使用 `HAVING` 子句直接过滤出异常数据。
* 示例:直接查询错误数超过 50 的服务。
```sql theme={null}
SELECT service_name, count(*) AS error_cnt
FROM "app-logs-*"
WHERE "@timestamp" > now() - INTERVAL 5 MINUTES AND log_level = 'ERROR'
GROUP BY service_name
HAVING count(*) > 50
```
2. **字段映射**:
* 在此模式下,标签字段和值字段为**非必填项**。如果都留空,Monitors 会将查询结果中的所有字段作为标签。
* 如果你只想用稳定字段标识告警对象,并把其他列作为排障上下文,请明确选择标签字段。参见[查询结果字段映射](/zh/monitors/alert-rules/query-result-fields)。
### 恢复逻辑
* **数据消失即恢复**:当 SQL 查询结果为空(即不再满足 HAVING 条件)时,引擎判定故障恢复。这是最常用的恢复方式。
* **恢复查询**:
* **场景**:有时"查不到数据"并不代表恢复(可能是日志采集挂了),或者需要更严格的恢复条件(如连续 N 分钟无错误)。
* **配置**:编写一条独立的 SQL 语句用于恢复判定。只要该查询能查到数据,就认为故障已恢复。
* **变量支持**:支持在恢复 SQL 中使用 `${label_name}` 引用告警事件的标签值,实现精准恢复检测。
### 优缺点分析
| 类型 | 说明 |
| ------ | ------------------------------------------ |
| **优点** | 利用 ES 集群的计算能力进行过滤,减少网络传输,性能更好 |
| **缺点** | 无法区分多级告警(如 Info/Warning),SQL 只能返回满足特定条件的数据 |
## 3. 数据缺失模式 (No Data)
此模式用于监控"预期应该有数据,但实际没有数据"的场景,常用于监控日志采集链路中断或周期性任务未执行。
### 配置方式
1. **查询语句**:编写一个预期应该持续返回数据的 SQL 查询。
* 示例:查询所有主机的日志上报心跳。
```sql theme={null}
SELECT host_name
FROM "heartbeat-logs-*"
WHERE "@timestamp" > now() - INTERVAL 5 MINUTES
GROUP BY host_name
```
2. **判定规则**:
* 引擎会周期性执行该 SQL。
* 如果某个 `host_name` 在之前的周期中出现过,但在当前周期(以及连续的 N 个周期)中不再出现在查询结果中,则触发"数据缺失"告警。
* 注意:这与 Data Exists 模式相反。Data Exists 是"查到数据就告警",No Data 是"查不到数据就告警"。
### 恢复逻辑
| 策略 | 说明 |
| ----------- | --------------------------------- |
| **数据出现即恢复** | 一旦该 `host_name` 重新出现在查询结果中,告警自动恢复 |
| **自动恢复时间** | 可配置超时时间(如 24 小时),超时后自动关闭告警 |
## 4. 案例说明
日志告警经常遇到如下需求:统计最近 5 分钟的 ERROR 日志数量,如果超过阈值则告警,同时在告警消息中展示最近一条 ERROR 日志作为样例。配置方案如下:
* **主告警条件**:使用 Threshold 模式,SQL 语句统计最近 5 分钟的 ERROR 日志数量,配置阈值条件。
* **关联查询**:配置一个关联查询,SQL 语句查询最近一条 ERROR 日志,使用 `${service_name}` 等变量限定具体服务。
* **规则备注描述**:在告警规则的备注描述中引用关联查询结果,使用 `$relates` 变量,把日志原文渲染出来。
# Loki
Source: https://docs.flashduty.com/zh/monitors/alert-rules/loki
配置 Loki 数据源的告警规则,支持 LogQL 查询语法
Monitors 支持 Loki 的 LogQL 查询语法,能够对日志数据进行聚合分析并触发告警。
## 核心概念
Loki 的查询语言 LogQL 分为两类:
| 类型 | 说明 |
| ------------------------- | ------------------------------------------- |
| **日志查询 (Log Queries)** | 返回日志行内容(Stream) |
| **指标查询 (Metric Queries)** | 对日志进行计数或聚合,如 `count_over_time` 返回数值(Vector) |
编写 LogQL 时,查询输入框会根据数据源自动补全标签名和标签值,帮助你快速定位日志流。
## 1. 阈值判定模式 (Threshold)
此模式适用于需要对日志聚合值进行多级阈值判定(如 Info/Warning/Critical)的场景。
### 配置方式
* **查询语句 (LogQL)**:编写返回数值向量的 LogQL(查询模式选择"做统计")
**示例**:统计最近 5 分钟内,`mysql` 任务中包含 `error` 关键字的日志条数:
```text theme={null}
count_over_time({job="mysql"} |= "error" [5m])
```
* **阈值条件**:
* **Critical**: `$A > 50` (5分钟内错误日志超过 50 条)
* **Warning**: `$A > 10` (5分钟内错误日志超过 10 条)
### 工作原理
引擎执行 LogQL 查询,获取带有标签的时间序列数据(Vector)。引擎遍历每个序列,提取数值与配置的阈值表达式进行比对。
### 恢复逻辑
| 策略 | 说明 |
| ---------- | ----------------------- |
| **自动恢复** | 当查询结果数值回落到阈值以下时,自动恢复 |
| **特定恢复条件** | 可配置如 `$A < 5`,避免在阈值附近震荡 |
| **恢复查询** | 支持独立 LogQL 用于恢复判定 |
## 2. 数据存在模式 (Data Exists)
此模式适用于习惯在 LogQL 中直接写过滤条件,或者只关心"是否有异常数据"的场景。推荐使用此模式做日志异常检测告警。
### 配置方式
* **查询语句 (LogQL)**:编写包含比较操作符的 LogQL,仅返回满足条件的数据
**示例**:直接筛选出错误率超过 5% 的服务:
```text theme={null}
count_over_time({job="ingress"} |= "error-code-500" [5m]) / count_over_time({job="ingress"} [5m]) * 100 > 5
```
* **判定规则**:只要 LogQL 查询返回了数据,即触发告警
### 优缺点分析
| 类型 | 说明 |
| ------ | ----------------------- |
| **优点** | 计算逻辑下推至 Loki 服务端,减少数据传输 |
| **缺点** | 无法区分告警级别,只能触发单一级别的告警 |
### 恢复逻辑
* **数据消失即恢复**:当 LogQL 查询结果为空时,判定恢复
* **恢复查询**:支持配置额外的查询语句用于辅助判断恢复状态
## 3. 数据缺失模式 (No Data)
此模式用于监控日志上报链路是否中断,或者预期应该持续产生的日志是否停止了。
### 配置方式
* **查询语句 (LogQL)**:编写预期应该一直有数据的查询
**示例**:统计所有主机的日志上报速率:
```text theme={null}
rate({job="node-logs"} [1m])
```
* **判定规则**:如果某个 Series(由标签唯一标识,如 `instance="host-1"`)在之前的周期中存在,但在当前及连续 N 个周期中查不到数据,则触发"数据缺失"告警
### 典型应用
* 监控 Promtail/Fluentd 等采集 Agent 是否停止工作
* 监控关键业务日志(如订单创建日志)是否异常中断
## 4. 使用查原文模式作为主查询
当你希望“查到符合条件的日志就告警”时,可以选择**查原文**模式,并使用**数据存在**判定。假设查询返回 `job`、`service`、`__time__`、`__log__` 等字段:
* **标签字段**:选择 `job`、`service` 等稳定维度,用于标识告警对象。
* **值字段**:数据存在模式下可以留空。如果使用阈值判定,请选择能转换为数字的字段。
* **附加信息**:`__time__`、`__log__` 和其他未选中的非值字段会自动随告警携带。
不要把 `__time__`、`__log__`、Trace ID 等频繁变化的字段配置为标签。否则每条日志都可能形成一个新的告警对象。
详细的默认行为、阈值引用方式和多查询对齐要求,请参见[查询结果字段映射](/zh/monitors/alert-rules/query-result-fields)。
## 5. 通过关联查询获取日志原文
告警时可以通过关联查询获取日志原文。但通常不建议获取太多,只获取 1 条作为日志样例放置到告警消息中。

关联查询的结果可以渲染在"备注描述"中,示例:
```text theme={null}
{{- if eq $status "firing" }}
error log count: {{ $value | printf "%.3f" }}
{{- range $x := $relates.R1}}
Loki log time: {{(nanoTime $x.Fields.__time__ 8).Format "2006-01-02T15:04:05Z07:00"}}
Loki Log line: {{$x.Fields.__log__}}
{{- end}}
{{- end}}
```
# MySQL
Source: https://docs.flashduty.com/zh/monitors/alert-rules/mysql
配置 MySQL 数据源的告警规则,支持标准 SQL 语法
Monitors 支持使用标准 SQL 语法对 MySQL 进行查询,并根据查询结果触发告警。
## 核心概念
| 配置项 | 说明 |
| -------- | ----------------------------------------- |
| **查询语言** | 使用标准 MySQL SQL 语法 |
| **字段处理** | 所有字段名自动转换为小写,配置时请使用小写字母 |
| **时间处理** | 建议使用 `now()`、`unix_timestamp()` 等函数进行时间过滤 |
## 1. 阈值判定模式
此模式适用于需要对聚合后的数值进行阈值比对的场景。
### 配置方式
1. **查询语句**:编写 SQL 聚合查询,返回数值列和(可选的)标签列。
* 示例:统计最近 5 分钟内,各服务的错误日志数量(假设有一个日志表)。
```sql theme={null}
SELECT
service_name,
count(*) AS error_cnt
FROM app_log
WHERE log_time > now() - INTERVAL 5 MINUTE AND level = 'error'
GROUP BY service_name
```
2. **字段映射**:
* **值字段**:选择 `error_cnt`,用于阈值判定。
* **标签字段**:选择 `service_name`,用于标识告警对象。明确选择标签字段后,其他非值字段会作为附加信息随告警携带。
* 详细规则请参见[查询结果字段映射](/zh/monitors/alert-rules/query-result-fields)。
3. **阈值条件**:
* 使用 `$A.field_name` 引用数值。
* 示例:`Critical: $A.error_cnt > 50`,`Warning: $A.error_cnt > 10`。
### 工作原理
Monitors 按标签字段区分告警对象,并使用值字段进行阈值判定。标签字段留空时,除值字段外的所有返回字段都会作为标签。
### 恢复逻辑
| 策略 | 说明 |
| ---------- | ----------------------------------- |
| **自动恢复** | 当数值不再满足任何告警阈值时,自动生成恢复事件 |
| **特定恢复条件** | 配置恢复表达式(如 `$A.error_cnt < 5`) |
| **恢复查询** | 独立 SQL 用于恢复判定,支持 `${label_name}` 变量 |
## 2. 数据存在模式
此模式适用于将过滤逻辑直接写在 SQL 中的场景。
### 配置方式
1. **查询语句**:在 SQL 中使用 `HAVING` 子句直接过滤出异常数据。
* 示例:直接查询错误数超过 50 的服务。
```sql theme={null}
SELECT
service_name,
count(*) AS error_cnt
FROM app_log
WHERE log_time > now() - INTERVAL 5 MINUTE AND level = 'error'
GROUP BY service_name
HAVING count(*) > 50
```
2. **判定规则**:只要 SQL 查询返回了数据(Result Set 不为空),即触发告警。
### 优缺点分析
| 类型 | 说明 |
| ------ | ---------------------------- |
| **优点** | 利用 MySQL 数据库的计算能力进行过滤,减少网络传输 |
| **缺点** | 无法区分多级告警 |
### 恢复逻辑
* **数据消失即恢复**:当 SQL 查询结果为空时,判定恢复
* **恢复查询**:支持配置额外的查询语句用于辅助判断恢复状态
## 3. 数据缺失模式
此模式用于监控"预期应该有数据,但实际没有数据"的场景。
### 配置方式
1. **查询语句**:编写一个预期应该持续返回数据的 SQL 查询。
* 示例:查询所有探针的心跳上报。
```sql theme={null}
SELECT probe_id, max(check_time) as last_seen
FROM probe_heartbeat
WHERE check_time > now() - INTERVAL 5 MINUTE
GROUP BY probe_id
```
2. **判定规则**:如果某个 `probe_id` 在之前的周期中出现过,但在当前及连续 N 个周期中查不到数据,则触发"数据缺失"告警。
## 4. 最佳实践
务必在 `WHERE` 子句中包含时间范围过滤,并确保时间字段上有索引,否则可能导致全表扫描。
推荐写法:`log_time > now() - INTERVAL 5 MINUTE`
Monitors 会将 MySQL 返回的列名统一转为小写。填写标签字段和值字段时,请始终使用小写字母。
# Oracle
Source: https://docs.flashduty.com/zh/monitors/alert-rules/oracle
配置 Oracle 数据源的告警规则,支持 Oracle SQL 语法
Monitors 支持使用标准 SQL 语法对 Oracle 进行查询,并根据查询结果触发告警。
## 核心概念
| 配置项 | 说明 |
| -------- | --------------------------------------- |
| **查询语言** | 使用 Oracle SQL 语法 |
| **字段处理** | 所有字段名自动转换为小写,配置时请使用小写字母 |
| **时间处理** | 建议使用 `SYSDATE`、`SYSTIMESTAMP` 等函数进行时间过滤 |
## 1. 阈值判定模式
此模式适用于需要对聚合后的数值进行阈值比对的场景。
### 配置方式
1. **查询语句**:编写 SQL 聚合查询,返回数值列和(可选的)标签列。
* 示例:统计最近 5 分钟内,各服务的错误日志数量。
```sql theme={null}
SELECT
service_name,
count(*) AS error_cnt
FROM app_log
WHERE log_time > SYSDATE - INTERVAL '5' MINUTE AND level = 'error'
GROUP BY service_name
```
2. **字段映射**:
* **值字段**:选择 `error_cnt`,用于阈值判定。
* **标签字段**:选择 `service_name`,用于标识告警对象。明确选择标签字段后,其他非值字段会作为附加信息随告警携带。
* 详细规则请参见[查询结果字段映射](/zh/monitors/alert-rules/query-result-fields)。
3. **阈值条件**:
* 使用 `$A.field_name` 引用数值。
* 示例:`Critical: $A.error_cnt > 50`,`Warning: $A.error_cnt > 10`。
### 工作原理
Monitors 按标签字段区分告警对象,并使用值字段进行阈值判定。标签字段留空时,除值字段外的所有返回字段都会作为标签。
### 恢复逻辑
| 策略 | 说明 |
| ---------- | ----------------------------------- |
| **自动恢复** | 当数值不再满足任何告警阈值时,自动生成恢复事件 |
| **特定恢复条件** | 配置恢复表达式(如 `$A.error_cnt < 5`) |
| **恢复查询** | 独立 SQL 用于恢复判定,支持 `${label_name}` 变量 |
## 2. 数据存在模式
此模式适用于将过滤逻辑直接写在 SQL 中的场景。
### 配置方式
1. **查询语句**:在 SQL 中使用 `HAVING` 子句直接过滤出异常数据。
* 示例:直接查询错误数超过 50 的服务。
```sql theme={null}
SELECT
service_name,
count(*) AS error_cnt
FROM app_log
WHERE log_time > SYSDATE - INTERVAL '5' MINUTE AND level = 'error'
GROUP BY service_name
HAVING count(*) > 50
```
2. **判定规则**:只要 SQL 查询返回了数据,即触发告警。
### 优缺点分析
| 类型 | 说明 |
| ------ | ----------------------------- |
| **优点** | 利用 Oracle 数据库的计算能力进行过滤,减少网络传输 |
| **缺点** | 无法区分多级告警 |
### 恢复逻辑
* **数据消失即恢复**:当 SQL 查询结果为空时,判定恢复
* **恢复查询**:支持配置额外的查询语句用于辅助判断恢复状态
## 3. 数据缺失模式
此模式用于监控"预期应该有数据,但实际没有数据"的场景。
### 配置方式
1. **查询语句**:编写一个预期应该持续返回数据的 SQL 查询。
* 示例:查询所有探针的心跳上报。
```sql theme={null}
SELECT probe_id, max(check_time) as last_seen
FROM probe_heartbeat
WHERE check_time > SYSDATE - INTERVAL '5' MINUTE
GROUP BY probe_id
```
2. **判定规则**:如果某个 `probe_id` 在之前的周期中出现过,但在当前及连续 N 个周期中查不到数据,则触发"数据缺失"告警。
## 4. 最佳实践
务必在 `WHERE` 子句中包含时间范围过滤,并确保时间字段上有索引,否则可能导致全表扫描。
推荐写法:`log_time > SYSDATE - INTERVAL '5' MINUTE`
Monitors 会将 Oracle 返回的列名统一转为小写。填写标签字段和值字段时,请始终使用小写字母。
# PostgreSQL
Source: https://docs.flashduty.com/zh/monitors/alert-rules/postgres
配置 PostgreSQL 数据源的告警规则,支持标准 SQL 语法
Monitors 支持使用标准 SQL 语法对 PostgreSQL 进行查询,并根据查询结果触发告警。
## 核心概念
| 配置项 | 说明 |
| -------- | ------------------------------------------ |
| **查询语言** | 使用 PostgreSQL SQL 语法 |
| **字段处理** | 所有字段名自动转换为小写,配置时请使用小写字母 |
| **时间处理** | 建议使用 `NOW()`、`CURRENT_TIMESTAMP` 等函数进行时间过滤 |
## 1. 阈值判定模式
此模式适用于需要对聚合后的数值进行阈值比对的场景。
### 配置方式
1. **查询语句**:编写 SQL 聚合查询,返回数值列和(可选的)标签列。
* 示例:统计最近 5 分钟内,各服务的错误日志数量。
```sql theme={null}
SELECT
service_name,
count(*) AS error_cnt
FROM app_log
WHERE log_time > NOW() - INTERVAL '5 minutes' AND level = 'error'
GROUP BY service_name
```
2. **字段映射**:
* **值字段**:选择 `error_cnt`,用于阈值判定。
* **标签字段**:选择 `service_name`,用于标识告警对象。明确选择标签字段后,其他非值字段会作为附加信息随告警携带。
* 详细规则请参见[查询结果字段映射](/zh/monitors/alert-rules/query-result-fields)。
3. **阈值条件**:
* 使用 `$A.field_name` 引用数值。
* 示例:`Critical: $A.error_cnt > 50`,`Warning: $A.error_cnt > 10`。
### 工作原理
Monitors 按标签字段区分告警对象,并使用值字段进行阈值判定。标签字段留空时,除值字段外的所有返回字段都会作为标签。
### 恢复逻辑
| 策略 | 说明 |
| ---------- | ----------------------------------- |
| **自动恢复** | 当数值不再满足任何告警阈值时,自动生成恢复事件 |
| **特定恢复条件** | 配置恢复表达式(如 `$A.error_cnt < 5`) |
| **恢复查询** | 独立 SQL 用于恢复判定,支持 `${label_name}` 变量 |
## 2. 数据存在模式
此模式适用于将过滤逻辑直接写在 SQL 中的场景。
### 配置方式
1. **查询语句**:在 SQL 中使用 `HAVING` 子句直接过滤出异常数据。
* 示例:直接查询错误数超过 50 的服务。
```sql theme={null}
SELECT
service_name,
count(*) AS error_cnt
FROM app_log
WHERE log_time > NOW() - INTERVAL '5 minutes' AND level = 'error'
GROUP BY service_name
HAVING count(*) > 50
```
2. **判定规则**:只要 SQL 查询返回了数据,即触发告警。
### 优缺点分析
| 类型 | 说明 |
| ------ | --------------------------------- |
| **优点** | 利用 PostgreSQL 数据库的计算能力进行过滤,减少网络传输 |
| **缺点** | 无法区分多级告警 |
### 恢复逻辑
* **数据消失即恢复**:当 SQL 查询结果为空时,判定恢复
* **恢复查询**:支持配置额外的查询语句用于辅助判断恢复状态
## 3. 数据缺失模式
此模式用于监控"预期应该有数据,但实际没有数据"的场景。
### 配置方式
1. **查询语句**:编写一个预期应该持续返回数据的 SQL 查询。
* 示例:查询所有探针的心跳上报。
```sql theme={null}
SELECT probe_id, max(check_time) as last_seen
FROM probe_heartbeat
WHERE check_time > NOW() - INTERVAL '5 minutes'
GROUP BY probe_id
```
2. **判定规则**:如果某个 `probe_id` 在之前的周期中出现过,但在当前及连续 N 个周期中查不到数据,则触发"数据缺失"告警。
## 4. 最佳实践
务必在 `WHERE` 子句中包含时间范围过滤,并确保时间字段上有索引,否则可能导致全表扫描。
推荐写法:`log_time > NOW() - INTERVAL '5 minutes'`
Monitors 会将 PostgreSQL 返回的列名统一转为小写。填写标签字段和值字段时,请始终使用小写字母。
# Prometheus
Source: https://docs.flashduty.com/zh/monitors/alert-rules/prometheus
配置 Prometheus 数据源的告警规则,支持 PromQL 查询语法
Monitors 兼容 Prometheus 的 PromQL 查询语法,并提供了灵活的告警判定与恢复机制。
## 核心概念
告警引擎支持三种核心判定模式:
查询返回原始指标数值,由告警引擎在内存中进行阈值比对
查询语句包含过滤条件,仅返回异常数据,查到数据即告警
用于监控数据上报中断的场景
## 1. 阈值判定模式
此模式适用于需要对同一指标进行多级告警(如 Info/Warning/Critical)或需要获取精确恢复值的场景。
### 配置方式
* **查询语句 (PromQL)**:编写 **不包含** 比较运算符的 PromQL,只返回指标数值。
* 示例:查询内存使用率
```promql theme={null}
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100
```
* **阈值条件**:在规则配置中定义不同严重级别的阈值表达式。变量 `$A` 代表查询结果的值。
* **Critical**:`$A > 90`(内存使用率超过 90% 触发严重告警)
* **Warning**:`$A > 80`(内存使用率超过 80% 触发警告告警)
### 多查询支持与数据关联
Monitors 支持在一个告警规则中配置多条查询语句(分别命名为 A、B、C...),并支持在阈值表达式中同时引用这些查询结果(如 `$A > 90 and $B < 50`)。
查询名称必须以英文字母开头,后面只能包含英文字母和数字,例如 `A`、`B2`。`R` 和 `__all__` 是保留名称,不能使用。
* **自动关联**:告警引擎会自动根据 **标签** 对不同查询语句返回的结果进行关联。
* **对齐要求**:只有当两条查询语句返回的数据包含 **完全相同** 的标签集时,它们才能被关联到同一组上下文中进行计算。
* 示例:查询 A 返回 `cpu_usage_percent{instance="host-1", job="node"}`,查询 B 返回 `mem_usage_percent{instance="host-1", job="node"}`,则 `$A` 和 `$B` 可以成功关联。
* 注意:如果查询 A 多了一个标签(如 `disk="/"`),而查询 B 没有,则无法关联。建议在 PromQL 中使用 `sum by (...)` 或 `avg by (...)` 等聚合操作,显式控制返回的标签,确保多条查询结果的标签一致。
* **表达式引用**:启用阈值判定时,Critical、Warning、Info 的表达式合计必须引用每个查询。每个级别不必引用全部查询,例如 Critical 使用 A、Warning 使用 B 是允许的。
### 工作原理
告警引擎周期性执行 PromQL,获取所有 Series 的当前值。随后,引擎遍历每个 Series,依次匹配 Critical、Warning、Info 条件。一旦满足某个级别的条件,即产生对应级别的告警事件。
### 恢复逻辑
支持多种恢复策略:
| 策略 | 说明 |
| ---------- | ------------------------------------ |
| **自动恢复** | 当最新查询结果不再满足任何告警阈值时,自动生成恢复事件 |
| **特定恢复条件** | 可配置额外的恢复表达式(如 `$A < 75`),避免在阈值附近频繁震荡 |
| **恢复查询** | 自定义一条 PromQL 用于恢复判定,查到数据即恢复 |
恢复查询语句支持嵌入变量(格式为 `${label_name}`),会被自动替换为告警事件中对应的标签值,实现针对具体告警对象的精确检测。
## 2. 数据存在模式 (Data Exists)
此模式与 Prometheus 原生告警规则(Alerting Rules)的行为一致。适用于习惯直接在 PromQL 中定义阈值的用户,或需要高性能处理大量 Series 的场景。
### 配置方式
* **查询语句**:编写 **包含** 比较运算符的 PromQL,仅筛选出异常数据。
* 示例:查询内存使用率超过 90% 的节点
```promql theme={null}
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100 > 90
```
* **判定规则**:无需额外配置阈值表达式。引擎只要查询到结果,即认为触发告警,查到几条数据就生成几个告警事件。
### 恢复逻辑
* **数据消失即恢复**:引擎周期性查询,如果某些数据查不到了,引擎判定对应的告警恢复。注意:数据的标识是基于标签集的。
* **恢复查询(可选)**:可配置一个独立的查询语句用于判定恢复(例如查询 `up{instance="${instance}"} == 1` 来确认服务恢复),查到数据才算恢复。这个 QL 中引入了变量 `${instance}`,会被替换为告警事件中的具体标签值。
### 优缺点分析
* **性能更优**:过滤逻辑下推至 Prometheus 服务端,减少了传输到告警引擎的数据量
* **迁移成本低**:可直接复用现有的 Prometheus Rule 语句
* **单一级别**:一条规则通常对应一个严重级别(如需区分 >90 和 >80,需配置两条规则)
* **现场值获取**:恢复时无法直接获取恢复时的具体数值(可使用关联查询获取)
## 3. 数据缺失模式 (No Data)
此模式专门用于监控监控对象是否存活或数据上报链路是否正常。
### 配置方式
* **查询语句**:编写预期应该一直存在的指标查询。
* 示例:`up{job="my-service"}`
* **判定规则**:如果连续 N 个周期无法查询到该 Series 的数据(注意:是完全查不到数据,而不是值为 0),则触发"数据缺失"告警。
* **引擎重启**:如果告警引擎(monitedge)重启,内存中的状态丢失,如果重启之前可以查到的数据重启之后恰好查不到了,则无法告警。重启之后会重新开始统计缺失周期。
### 典型应用
* 监控 Exporter 宕机。
* 监控埋点上报服务中断。
* 监控批处理任务未按时执行。
### 子模式一:按 Series 监控(Per-Series)
当某个 Series **曾经可以查到数据,后来连续 N 次查不到**时触发告警。这是默认的数据缺失检测模式。
* 要求:目标 Series 必须至少被引擎观测到一次,才能建立基线。
* 局限:如果某个监控对象从来没有上报过数据(例如:Exporter 安装后从未成功采集到一条指标),此模式无法触发告警。
* 字段:`enabled: true`,`severity`(`Critical | Warning | Info`)。
### 子模式二:全空结果告警(Alert on Empty Result)
当**所有查询在连续 N 次检查中均返回空结果**时触发告警。此模式专门覆盖"数据从未上报过"的场景,弥补按 Series 模式的盲区。
* 适用场景:新部署的 Exporter 从未成功采集到指标;批处理任务从未产生过输出;希望在目标完全不存在时立即告警。
* 字段:`alert_on_empty_result: true`,`alert_on_empty_result_severity`(`Critical | Warning | Info`)。
* 恢复逻辑:一旦任意查询返回非空结果,经过连续 `recovery_check_times` 次确认后自动恢复。
两个子模式可以同时开启,并且相互独立运行。
### 对比 Prometheus 原生的 `absent()` 函数
| 方式 | 说明 |
| --------------------- | ----------------------------- |
| Prometheus `absent()` | 需要把每个标识类的标签组合都列举出来,多个实例需多条语句 |
| Monitors 按 Series 模式 | 只需一条查询语句,自动对所有已观测 Series 进行监控 |
| Monitors 全空结果模式(新) | 无需 Series 曾存在,数据从未上报也能触发告警 |
## 高级配置
### 标签与变量
Monitors 会自动解析 Prometheus 返回的 Labels。在 **恢复查询** 或 **关联查询** 中,可以使用 `${label_name}` 引用标签值。
比如某个告警规则查询语句返回的结果包含标签 `instance="host-1"` 和 `job="node"`,则在恢复查询中可以这样写:
```
up{instance="${instance}", job="${job}"} == 1
```
告警引擎执行时,会将 `${instance}` 替换为 `host-1`,`${job}` 替换为 `node`,也就是告警事件标签中的具体值。
### 关联查询 (Enrichment)
为了丰富告警通知的内容,可以配置"关联查询"。关联查询不参与告警判定,仅用于获取额外信息。
* **场景**:CPU 告警时,同时查询该机器的 `mem_usage_percent` 负载情况,展示在告警详情中,辅助排查。
* **变量**:关联查询中支持 `${label_name}` 变量,用于针对具体告警对象查询。
* **结果展示**:关联查询的结果可以在告警规则的备注描述中引用,其变量是 `$relates`,您可以查看 **备注描述** 的详细使用说明。
# 查询结果字段映射
Source: https://docs.flashduty.com/zh/monitors/alert-rules/query-result-fields
说明如何把 SQL 和原文日志查询结果配置为值字段、标签字段和告警附加信息。
MySQL、PostgreSQL、Oracle、ClickHouse、Elasticsearch、SLS 等表格型查询,以及 Loki 和 VictoriaLogs 的**查原文**模式,都会返回包含多列数据的结果。你可以通过**值字段**和**标签字段**决定每一列的用途;其余列无需单独配置,会作为附加信息随告警携带。
本页描述的完整字段映射行为需要 monit-edge `v0.53.0` 或以上版本,尤其是将查询附加信息统一命名为 `$<查询名称>.<字段名称>` 的能力。使用这些配置前,请先将告警引擎升级到 `v0.53.0` 或更高版本。
## 字段如何分类
假设查询 A 返回以下数据:
| service | error\_count | sample\_message | latest\_at |
| -------- | -----------: | ------------------ | ------------------- |
| checkout | 27 | connection timeout | 2026-07-30 21:00:00 |
推荐配置:
| 字段用途 | 配置或结果 | 作用 |
| ---- | ---------------------------- | ----------------------------- |
| 值字段 | `error_count` | 作为数值参与阈值判定,也会保存在告警事件中。 |
| 标签字段 | `service` | 标识告警对象。同一组标签对应同一个告警实例。 |
| 附加信息 | `sample_message`、`latest_at` | 自动随告警携带,用于补充排障上下文,但不参与告警身份计算。 |
附加信息不是需要填写的第三组字段。只要你明确选择了标签字段,查询结果中既不是标签字段、也不是值字段的列就会自动成为附加信息。
### 值字段
值字段应返回可转换为数字的内容。启用**阈值判定**时必须至少配置一个值字段;使用**数据存在**或**数据缺失**模式时可以不配置。
* 值字段名称不能为空,也不能包含 `.`。
* 同一个字段不能同时配置为值字段和标签字段。
* 请先预览数据,按预览结果填写真实字段名。保存规则时不会连接数据源确认该列一定存在。
### 标签字段
标签字段决定告警身份,也决定不同查询的结果能否对应。请选择服务、集群、主机、实例等稳定维度。
* 标签字段名称不能为空,同一个字段不要重复添加。
* 同一个字段不能同时配置为标签字段和值字段。
不建议把以下内容配置为标签:
* 时间戳
* 日志原文或错误消息
* Trace ID、请求 ID 等每次都可能变化的值
* 其他高基数字段
这些字段变化频繁,作为标签时可能让每一行数据形成不同的告警,或者导致多个查询无法对齐。把它们留作附加信息更合适。
### 标签字段留空时
为了兼容已有规则,标签字段留空时,查询结果中除值字段外的所有字段都会作为标签,不会再产生查询附加信息。
| 标签字段配置 | 标签 | 附加信息 |
| ------ | ------ | ------ |
| 留空 | 所有非值字段 | 无 |
| 明确选择 | 仅选择的字段 | 其余非值字段 |
对于日志原文查询,建议明确选择标签字段。否则时间戳和日志正文也可能成为标签,造成大量彼此独立的告警。
SLS 查询结果自带的 `__source__` 和 `__time__` 不会在标签字段留空时自动成为标签。如需使用这些内容,建议在查询中设置别名,再按普通字段配置。
## 在阈值表达式中引用值
查询名称就是阈值变量的前缀。例如,查询 A 的值字段为 `error_count`。
### 一个值字段
只配置一个值字段时,可以使用完整写法,也可以直接使用查询变量:
```text theme={null}
Critical: $A.error_count > 20
Warning: $A > 10
```
两种写法引用的是同一个值。
### 多个值字段
如果查询 A 同时配置了 `error_count` 和 `latency_ms`,必须写明字段名称:
```text theme={null}
Critical: $A.error_count > 20 or $A.latency_ms > 1000
```
此时不能直接写 `$A > 20`。表达式中的字段也必须已配置为该查询的值字段。这个要求同样适用于“结果满足条件才算恢复”的恢复表达式。
### 查询名称
查询名称必须以英文字母开头,后面只能包含英文字母和数字,例如 `A`、`B2` 或 `Latency`。`R` 和 `__all__` 是保留名称,不能使用。
## 多个查询如何对齐
在**阈值判定**模式中,查询 A、B 的结果只有在标签字段名和标签值都完全相同时,才能进入同一次阈值计算。
以下结果可以一一对应:
| 查询 | service | cluster | 值字段 |
| -- | -------- | ------- | ----------------: |
| A | checkout | prod | `error_count=27` |
| B | checkout | prod | `latency_ms=1350` |
你可以配置:
```text theme={null}
Critical: $A.error_count > 20 and $B.latency_ms > 1000
```
如果查询 B 没有 `cluster` 标签,或者 `cluster` 的值不同,这两行不会合并计算。请确保:
1. 各查询选择相同的标签字段,并返回相同的标签值。
2. 每个查询中,一个标签组合只对应一行结果。必要时先在查询语句中聚合。
3. 错误消息、日志正文等变化字段作为附加信息,不要作为标签。
启用阈值判定并配置多个查询时,Critical、Warning、Info 的告警阈值表达式合计必须引用全部查询。并非每个级别都必须引用全部查询,例如 Critical 使用 A、Warning 使用 B 是允许的;不参与任何告警阈值的查询应删除。
## 在备注描述中使用附加信息
查询附加信息会进入 `$annotations`,并始终使用 `$<查询名称>.<字段名称>` 作为 key。无论配置了几个查询,也无论使用阈值判定、数据存在还是数据缺失模式,写法都相同:
```gotemplate theme={null}
{{ index $annotations "$A.sample_message" }}
{{ index $annotations "$B.sample_message" }}
```
`$` 前缀用于标识查询产生的字段。规则中手工配置的自定义字段名称不能以 `$` 开头。更多变量和示例请参见[备注模板](/zh/monitors/alert-rules/description-template)。
数据缺失告警会携带该告警对象最后一次成功查询时的附加信息。如果查询从未返回过数据,则没有可携带的查询附加信息。
## 查询结果行数上限
所有告警规则查询都有 **1000 行** 的硬性上限,包括阈值判定、数据存在、数据缺失的判定查询,以及恢复查询和关联查询。查询返回超过 1000 行时,该查询直接失败(错误信息 `too many rows`),本次判定报错,不会产生告警。
该上限对所有数据源类型生效(MySQL、PostgreSQL、Oracle、ClickHouse、Elasticsearch、SLS、Loki、VictoriaLogs、Prometheus 等)。高基数 Prometheus 查询(超过 1000 条序列)或返回大结果集的 SQL 查询会因此报错而不再产生告警。
建议在数据源侧完成聚合,而不是让一条规则查询返回大量行:
* SQL 查询使用 `GROUP BY`、聚合函数或 `LIMIT` 收窄结果
* PromQL 使用聚合算子(如 `sum`、`max`、`topk`)或收窄时间范围
* 将查询拆分为多个规则,分别覆盖不同的维度子集
每一行查询结果都可能生成一个告警实例,在数据源中聚合既能规避行数上限,也能避免产生难以管理的海量告警。
## 适用范围
本页适用于:
* MySQL、PostgreSQL、Oracle、ClickHouse、Elasticsearch 和 SLS 查询
* Loki 和 VictoriaLogs 的**查原文**主查询
Loki 和 VictoriaLogs 的**做统计**模式会直接返回带标签的时序数据,不需要手工映射这些结果字段。
# SLS
Source: https://docs.flashduty.com/zh/monitors/alert-rules/sls
配置阿里云日志服务 (SLS) 数据源的告警规则
Monitors 通过 SLS 的 SQL 查询接口(GetLogsV3)获取数据,并根据查询结果触发告警。
## 核心概念
| 配置项 | 说明 |
| -------- | -------------------------------------------- |
| **查询语言** | 使用 SLS SQL 语法 |
| **必填参数** | 每条查询必须指定 `sls.project` 和 `sls.logstore` |
| **时间范围** | 由 API 参数控制,无需在 SQL 中写 `WHERE __time__ > ...` |
| **字段处理** | `__source__` 和 `__time__` 字段默认被忽略 |
## 1. 阈值判定模式
此模式适用于需要对聚合后的数值进行阈值比对的场景。
### 配置方式
1. **查询语句**:编写 SLS SQL 聚合查询。
* 示例:统计最近 15 分钟内,各主机的错误日志数量。
```sql theme={null}
* | SELECT host, count(*) as error_cnt WHERE level = 'ERROR' GROUP BY host
```
2. **查询参数**:
* `sls.project`:(必填)项目名称。
* `sls.logstore`:(必填)日志库名称。
* `sls.timespan.value`:(选填)时间跨度数值,默认为 15。
* `sls.timespan.unit`:(选填)时间跨度单位,支持 `s`(秒)、`m`(分)、`h`(时)、`d`(天)。默认为 `m`。
3. **字段映射**:
* **值字段**:选择 `error_cnt`,用于阈值判定。
* **标签字段**:选择 `host`,用于标识告警对象。明确选择标签字段后,其他非值字段会作为附加信息随告警携带。
* 详细规则请参见[查询结果字段映射](/zh/monitors/alert-rules/query-result-fields)。
4. **阈值条件**:
* 使用 `$A.field_name` 引用数值。
* 示例:`Critical: $A.error_cnt > 50`,`Warning: $A.error_cnt > 10`。
### 工作原理
Monitors 按配置的时间范围执行 SLS 查询,按标签字段区分告警对象,并使用值字段进行阈值判定。标签字段留空时,除值字段外的返回字段会作为标签。
### 恢复逻辑
| 策略 | 说明 |
| ---------- | ----------------------------------- |
| **自动恢复** | 当数值不再满足任何告警阈值时,自动恢复 |
| **特定恢复条件** | 配置恢复表达式(如 `$A.error_cnt < 5`) |
| **恢复查询** | 独立 SQL 用于恢复判定,支持 `${label_name}` 变量 |
## 2. 数据存在模式
此模式适用于将过滤逻辑直接写在 SQL 中的场景。
### 配置方式
1. **查询语句**:使用 `HAVING` 子句过滤异常数据。
* 示例:查询错误数超过 50 的主机。
```sql theme={null}
* | SELECT host, count(*) as error_cnt WHERE level = 'ERROR' GROUP BY host HAVING error_cnt > 50
```
2. **查询参数**:同上,需配置 `sls.project` 和 `sls.logstore`。
3. **判定规则**:只要查询返回了数据,即触发告警。
### 优缺点分析
| 类型 | 说明 |
| ------ | ---------------------- |
| **优点** | 利用 SLS 服务端的计算能力,减少数据传输 |
| **缺点** | 无法区分多级告警 |
### 恢复逻辑
* **数据消失即恢复**:当查询结果为空时,判定恢复
* **恢复查询**:支持配置额外的查询语句
## 3. 数据缺失模式
此模式用于监控"预期应该有数据,但实际没有数据"的场景。
### 配置方式
1. **查询语句**:编写一个预期应该持续返回数据的查询。
* 示例:查询所有主机的日志上报心跳。
```sql theme={null}
* | SELECT host, max(__time__) as last_seen GROUP BY host
```
2. **判定规则**:如果某个 `host` 在之前的周期中出现过,但在当前及连续 N 个周期中查不到数据,则触发"数据缺失"告警。
## 4. 高级配置
如果需要使用 SLS 的增强 SQL 语法,在查询参数中添加:`sls.powersql: true`
默认查询最近 15 分钟的数据。可通过参数调整:
| 参数 | 说明 |
| -------------------- | -------------------------------- |
| `sls.timespan.value` | 时间跨度数值,如 `60` |
| `sls.timespan.unit` | 时间单位:`s`(秒)、`m`(分)、`h`(时)、`d`(天) |
不要在 SQL 中使用 `__time__` 进行过滤,引擎会自动根据参数设置时间范围。
仅用于调试,不要配置在生产规则中:
| 参数 | 说明 |
| ---------- | -------- |
| `sls.from` | 开始时间戳(秒) |
| `sls.to` | 结束时间戳(秒) |
# VictoriaLogs
Source: https://docs.flashduty.com/zh/monitors/alert-rules/victorialogs
配置 VictoriaLogs 数据源的告警规则
Monitors 通过 HTTP 查询 VictoriaLogs,支持查询日志原文、做统计分析,并基于结果进行阈值判定和数据存在/缺失判断。
## 1. 前置说明
### 查询模式
调用 `/select/logsql/query` 接口,返回二维表格数据。
| 配置项 | 说明 |
| ------ | ---------------------------------------------------------------- |
| 查询语句 | 如 `error \| fields _time, _stream, _msg \| sort by (_time) desc` |
| 返回条目限制 | 限制最大返回行数,最大可设置为 100 |
| 时间范围 | 指定查询的时间窗口,例如"最近 5 分钟" |
| 标签字段 | 选择标识告警对象的稳定字段;其他非值字段作为附加信息 |
| 值字段 | 阈值判定模式下必填 |
调用 `/select/logsql/stats_query` 接口,返回 Prometheus 协议格式数据。
| 配置项 | 说明 |
| ---- | ----------------------------------------------- |
| 查询语句 | 如 `_time:1d \| stats by (level) count(*) total` |
查询语句中必须包含 `_time` 过滤条件(如 `_time:5m`),否则会查全部数据导致性能问题。
VictoriaLogs 数据源最推荐使用"数据存在模式",最适合日志场景。
## 2. 阈值判定模式 (Threshold)
**查原文**和**做统计**两种查询模式都可以使用。下面分别举例说明。
### 2.1 查原文示例
查询语句示例:
```
level:ERROR | stats by (level) count(*) total
```
得到的结果类似:
| level | total |
| ----- | ----- |
| ERROR | 150 |
将标签字段配置为 `level`,值字段配置为 `total`。如果结果还包含日志样例等其他列,这些列会作为附加信息随告警携带。不同级别的阈值配置示例:
* Warning:`$A.total >= 50` 或者简写为 `$A >= 50`(因为只有 total 这一个值字段)
* Critical:`$A.total >= 100` 或者简写为 `$A >= 100`(因为只有 total 这一个值字段)
### 2.2 做统计示例
查询语句示例:
`_time:1d and level:ERROR | stats by (level) count(*) total`
得到的结果遵从 Prometheus 协议格式:
```
total{level="ERROR"} 150
```
不同阈值不同级别的配置示例:
* Warning:`$A.total >= 50` 或者简写为 `$A >= 50`(因为只有 total 这一个指标字段)
* Critical:`$A.total >= 100` 或者简写为 `$A >= 100`(因为只有 total 这一个指标字段)
### 2.3 恢复逻辑
| 策略 | 说明 |
| ---------- | -------------------------------- |
| **自动恢复** | 当数值不再满足任何告警阈值时,自动生成恢复事件 |
| **特定恢复条件** | 配置恢复表达式(如 `$A.total < 10`),减少抖动 |
| **恢复查询** | 独立查询用于恢复判定,支持 `${label_name}` 变量 |
## 3. 数据存在模式 (Data Exists)
这是**最推荐的 VictoriaLogs 告警配置方式**,因为日志场景更适合采用"有异常数据就告警"的模式。
此模式将过滤逻辑全部写在 VictoriaLogs 查询中,Monitors 只负责判断"是否有数据返回"。
**查询语句示例(做统计模式):**
```
_time:15m and level:ERROR | stats by (level) count(*) total | filter total:>10
```
其中 `| filter total:>10` 用于筛选出 `total` 大于 10 的数据。只要有满足该条件的数据行返回,Monitors 就会触发告警;如果没有任何数据行满足该条件,则认为告警恢复。
使用**查原文**模式时,建议选择 `service`、`host` 等稳定字段作为标签字段,把 `_time`、`_msg` 和其他日志上下文留作附加信息。数据存在模式不要求配置值字段。
标签字段留空时,除值字段外的所有返回字段都会成为标签。时间戳、日志正文等频繁变化的字段可能让每条日志形成不同的告警对象。
详细规则请参见[查询结果字段映射](/zh/monitors/alert-rules/query-result-fields)。
## 4. 数据缺失模式 (No Data)
数据缺失模式用于监控"原本应该持续产生的日志不再出现"的情况,常见于:
* 应用实例不再产生日志(可能是进程退出)
* 日志采集链路异常(如 agent 宕机或输出阻塞)
### 配置示例
查询语句(**做统计**模式):
```
_time:15m and level:INFO | stats by (level) count(*) total
```
场景:某个服务应该一直都有 INFO 日志输出,如果在最近 15 分钟内没有任何 INFO 日志产生,就触发告警。
## 5. 获取告警时日志原文
告警查询条件通常使用 “做统计” 模式,这种模式没有返回日志原文。Monitors 支持在告警规则中配置“关联查询”,用于在告警触发时额外查询日志原文。

“关联查询”的结果可以渲染在 “备注描述” 中,示例:
```
{{- if eq $status "firing" }}
triggered value: {{ $value | printf "%.3f" }}
{{- range $x := $relates.R1}}
{{- range $k, $v := $x.Fields }}
{{- if eq $k "_time" }}
{{ $k }} : {{ timeFormat $v "2006-01-02T15:04:05Z07:00" 8 }}
{{- else }}
{{ $k }} : {{ $v }}
{{- end }}
{{- end }}
{{- end}}
{{- else}}
Recovered
{{- end}}
```
# 数据源管理
Source: https://docs.flashduty.com/zh/monitors/data-sources/data-sources
配置和管理 Monitors 的数据源,包括 Prometheus、Elasticsearch、Loki、ClickHouse、MySQL、Oracle、PostgreSQL、SLS、VictoriaLogs 等类型
数据源是告警引擎查询数据的来源。你需要先配置数据源,告警引擎才能从中读取数据进行异常判定。
**菜单入口**:数据源
## 支持的数据源类型
Monitors 支持以下 9 种数据源类型:
| 类型 | 说明 |
| ----------------- | ------------------------------- |
| **Prometheus** | 时序数据库,通过 PromQL 查询 |
| **Elasticsearch** | 分布式搜索与分析引擎 |
| **Loki** | 轻量级日志聚合系统 |
| **ClickHouse** | 列式分析数据库 |
| **MySQL** | 关系型数据库 |
| **Oracle** | 关系型数据库 |
| **PostgreSQL** | 关系型数据库 |
| **SLS** | 阿里云日志服务 |
| **VictoriaLogs** | 日志数据库,VictoriaMetrics 生态的日志解决方案 |
## 数据源列表
数据源列表展示所有已配置的数据源,包括以下信息:
* **名称**:数据源的标识名称
* **类型**:数据源类型及图标
* **连接地址**:数据源的访问地址
* **关联告警引擎**:绑定的告警引擎集群名称,附带引擎在线状态指示
* **备注**:补充说明
你可以通过搜索框按名称或类型过滤数据源。列表每 5 秒自动刷新,实时反映引擎连接状态。
## 新建数据源
点击**新建**按钮,在表单顶部选择数据源类型(如 Prometheus、MySQL 等)。
| 配置项 | 说明 |
| ---------- | -------------------------------------------- |
| **名称** | 数据源的唯一标识名称,告警规则可通过名称通配或精确匹配两种方式关联数据源(详见下方说明) |
| **备注** | 可选的补充说明 |
| **关联告警引擎** | 选择负责查询该数据源的引擎集群,通常选择与数据源同机房的集群 |
根据数据源类型填写对应的连接参数,详见下方各类型说明。
点击**确定**完成创建。
### 告警规则关联数据源的两种方式
告警规则支持两种方式绑定数据源,可以同时使用,至少填写一种。规则会作用于两种方式匹配到的所有数据源的并集。
| 绑定方式 | 字段 | 匹配逻辑 | 适用场景 |
| -------- | ----------- | ----------------------------------------------- | -------------------------- |
| **名称通配** | `数据源(名称通配)` | 按名称做通配符匹配。`*` 匹配所有数据源;`Prom*` 匹配名称以 Prom 开头的数据源 | 需要动态匹配一批数据源,例如同类型数据源统一命名前缀 |
| **精确匹配** | `数据源(精确匹配)` | 按数据源 ID 精确关联,从下拉列表中选择具体数据源 | 需要精确绑定特定数据源,不受数据源改名影响 |
名称通配方式存储的是名称字符串,如果数据源改名,已有的通配规则可能不再匹配。精确匹配方式存储的是数据源 ID,不受改名影响。如果对稳定性要求高,建议优先使用精确匹配。
## 各数据源类型配置
### Prometheus
| 配置项 | 说明 |
| ------------------------ | ------------------------------------------- |
| **Server URL** | Prometheus 服务地址,如 `http://localhost:9090` |
| **Headers** | 自定义 HTTP 请求头,支持添加多组 Key-Value |
| **Params** | 自定义 URL 查询参数,支持添加多组 Key-Value |
| **Basic Authentication** | 启用后需填写用户名和密码 |
| **使用自定义 CA 证书** | 勾选后填写 CA 证书内容;留空时使用告警引擎所在操作系统的系统信任库 |
| **启用客户端证书认证(mTLS)** | 勾选后填写客户端证书和客户端私钥,两者必须成对填写 |
| **服务端名称(可选)** | 用于 SNI 和证书主机名校验;留空时从连接地址推断 |
| **最低 / 最高 TLS 版本** | 可选 TLS 1.0、1.1、1.2、1.3,默认为系统默认;最低版本不得高于最高版本 |
| **跳过服务端证书校验** | 勾选后不校验服务端证书 |
### MySQL / Oracle / PostgreSQL
关系型数据库共享相似的配置结构:
| 配置项 | 说明 | 默认值 |
| ------------- | ------------------------------------------------------------------------------------- | ---- |
| **连接地址** | 数据库地址,如 `localhost:3306`(MySQL)、`localhost:1521`(Oracle)、`localhost:5432`(PostgreSQL) | - |
| **最大连接数** | 连接池最大打开连接数 | 32 |
| **空闲连接数** | 连接池最大空闲连接数 | 4 |
| **连接存活时长(秒)** | 连接最大存活时间 | 600 |
| **超时时间(毫秒)** | 查询超时时间 | 5000 |
| **用户名** | 数据库用户名 | - |
| **密码** | 数据库密码 | - |
Oracle 仅使用上述基础连接配置。MySQL 和 PostgreSQL 额外支持 TLS/SSL 加密连接,通过 **TLS/SSL 模式** 下拉框选择。
#### MySQL 的 TLS/SSL 模式
| 模式 | 说明 |
| ---------------------------- | ------------------------------------------- |
| **不启用 TLS**(disable) | 连接不经过 TLS 加密 |
| **加密连接,不校验证书**(require) | 强制使用 TLS 加密,但不验证数据库服务器身份;该模式下不允许配置自定义 CA 证书 |
| **校验证书和主机名**(verify-full,推荐) | 验证服务端证书的签发机构,并校验证书中的主机名;该模式下可配置自定义 CA 证书 |
选择非「不启用 TLS」模式后,还可以启用客户端证书认证(mTLS,客户端证书和客户端私钥需成对填写)、填写服务端名称,以及设置最低 / 最高 TLS 版本。选择「校验证书和主机名」模式时,连接地址建议填写与服务端证书匹配的数据库域名,不要使用 IP 地址。
设置非「不启用 TLS」模式时,关联告警引擎集群内所有已注册的 Edge 实例必须为 v0.51.0 或更高版本。
#### PostgreSQL 的 TLS/SSL 模式
| 模式 | 说明 |
| ---------------------------- | ------------------------------------------- |
| **不启用 TLS**(disable) | 连接不经过 TLS 加密 |
| **加密连接,不校验证书**(require) | 强制使用 TLS 加密,但不验证数据库服务器身份;该模式下不允许配置自定义 CA 证书 |
| **校验证书颁发机构**(verify-ca) | 验证服务端证书是否由可信的证书颁发机构签发,但不校验证书中的主机名 |
| **校验证书和主机名**(verify-full,推荐) | 验证服务端证书的签发机构,并校验证书中的主机名是否与连接地址一致 |
在「校验证书颁发机构」和「校验证书和主机名」模式下可选填自定义 CA 证书,留空时使用告警引擎所在操作系统的系统信任库;非「不启用 TLS」模式下均可启用客户端证书认证(mTLS)。选择「校验证书和主机名」模式时,连接地址请填写与服务端证书匹配的数据库域名,不要使用 IP 地址。
设置非「不启用 TLS」模式时,关联告警引擎集群内所有已注册的 Edge 实例必须为 v0.50.0 或更高版本。
### Elasticsearch / Loki / ClickHouse / SLS / VictoriaLogs
这些数据源的连接配置与 Prometheus 类似,包括服务地址、认证和 TLS 配置。其中 VictoriaLogs 的默认服务地址为 `http://localhost:9428`。具体参数请参考创建表单中的说明。
## 在 Edge 本地引用凭据
使用 `v0.46.0` 或更高版本的 Edge 时,你可以在受支持的数据源连接字段中使用环境变量引用,而不必将凭据直接写入数据源配置。Edge 会在本地进程中解析引用值;解析后的凭据不会回写到同步的数据源配置、调试输出或 API 载荷中。
在每个负责查询该数据源的 Edge 进程环境中设置凭据。例如,为 SLS 设置 `SLS_ACCESS_KEY_ID` 和 `SLS_ACCESS_KEY_SECRET`。修改环境变量后,重启 Edge 进程使新值生效。
编辑数据源时,在受支持的认证或连接字段中填写 `${env:变量名}`。例如,SLS 的 **AccessKey ID** 与 **AccessKey Secret** 可以分别填写 `${env:SLS_ACCESS_KEY_ID}` 和 `${env:SLS_ACCESS_KEY_SECRET}`。
保存数据源后,使用 **测试** 验证连接。每个引用的变量都必须存在于对应 Edge 进程环境中。
变量名必须以大写字母或下划线开头,后续只能包含大写字母、数字或下划线,例如 `SLS_ACCESS_KEY_SECRET`。
不能在数据源**连接地址**中使用环境变量引用;Prometheus、Loki 与 VictoriaLogs 的 **Params** 也不支持引用。请只在受支持的认证和连接字段中使用该语法。
## 测试数据源
在数据源列表中,点击对应数据源的**测试**按钮,可以打开查询预览窗口,验证数据源连接是否正常并预览查询结果。
## 编辑和删除
* **编辑**:在数据源列表中点击**编辑**按钮,修改数据源配置后保存。
* **删除**:在数据源列表中点击**删除**按钮,确认后删除数据源。
删除数据源前,请确保没有告警规则引用该数据源,否则相关告警规则将无法正常执行。
# 告警引擎管理
Source: https://docs.flashduty.com/zh/monitors/engine/engine
管理告警引擎的安装、状态监控和 API Key,确保告警检测持续运行
告警引擎(`monitedge`)是部署在你私有网络中的核心组件,负责从 Flashduty SaaS 端同步告警规则,从本地数据源读取数据进行异常判定,并将告警事件推送到 SaaS 端进行后续处理。
**菜单入口**:告警引擎
告警引擎页面包含三个标签页:**告警引擎状态**、**引擎安装/升级**、**引擎失联告警**。
## 告警引擎状态
展示所有已注册的告警引擎实例信息,列表每 5 秒自动刷新。
| 列信息 | 说明 |
| ----------- | ------------------------------ |
| **引擎集群名字** | 同名实例组成一个集群,共同分片处理告警规则 |
| **引擎实例 IP** | 实例运行的 IP 地址 |
| **引擎实例端口** | 实例监听的端口号 |
| **上次心跳时间** | 最近一次向 SaaS 上报心跳的时间,附带在线/离线状态指示 |
| **引擎实例版本** | 当前运行的 `monitedge` 版本号 |
引擎实例超过 30 秒未上报心跳,状态会标记为离线(红色)。离线的引擎实例会显示**删除**按钮,你可以点击清除已不存在的实例记录。
### 集群数据源 MD5 校验
同一集群内的多个引擎实例应该使用相同的数据源配置。如果系统检测到集群内不同实例的数据源配置 MD5 不一致,会在集群名称前显示红色警示标记,提示你尽快检查引擎配置。
## 引擎安装/升级
提供一键生成安装和升级命令的功能,支持三种部署方式。
### 安装配置
选择 **Linux**、**Docker** 或 **Kubernetes**。
同机房部署多个实例时,使用相同的集群名字可组成高可用集群。不同机房使用不同的集群名字。
一般每个机房分别部署一套告警引擎集群,集群名字建议设置为机房名称。
从下拉列表中选择已有的 API Key,或点击**管理 API Key**创建新的 Key。
页面会根据你的选择自动生成安装命令和升级命令,复制后在目标机器上执行即可。
### 部署方式对比
| 部署方式 | 适用场景 |
| -------------- | ----------------------------- |
| **Linux** | 直接在物理机或虚拟机上安装,使用 systemd 管理进程 |
| **Docker** | 容器化部署,适合已有 Docker 环境的场景 |
| **Kubernetes** | 适合云原生环境,以 Deployment 方式部署 |
## API Key 管理
API Key 用于告警引擎与 SaaS 端的身份认证。你可以在引擎安装/升级页面点击**管理 API Key**打开管理面板。
### 功能说明
| 操作 | 说明 |
| ------- | ---------------------------------------- |
| **新增** | 创建新的 API Key,需要输入名称。每个租户最多创建 5 个 API Key |
| **重命名** | 点击 Key 名称即可编辑修改 |
| **删除** | 删除不再使用的 API Key,需要具备 API Key 删除权限 |
管理面板中还会展示每个 API Key 的当前状态:
| 状态 | 说明 |
| ------------- | --------------------------------------- |
| **启用中**(绿色图标) | API Key 正常工作,引擎实例可以使用该 Key 与 SaaS 端通信 |
| **禁用中**(黄色图标) | API Key 已被禁用,使用该 Key 的引擎实例将无法与 SaaS 端通信 |
删除 API Key 后,使用该 Key 的所有引擎实例将无法与 SaaS 端通信。请确保在删除前已将相关引擎切换到其他有效的 API Key。
### 权限要求
* 创建 API Key 需要 `ApiKeyCreate` 权限
* 删除 API Key 需要 `ApiKeyDelete` 权限
如果你没有操作权限,请联系管理员前往访问控制页面授权。
## 引擎 CLI 参数参考
`monitedge` 二进制通过命令行参数进行配置。以下是与告警推送相关的核心参数。
### 告警推送参数
| 参数 | 默认值 | 说明 |
| ---------------------------------------- | ---------------------------- | ------------------------------------------------------------------------- |
| `alerter.serverURL` | `https://api.flashcat.cloud` | FlashDuty SaaS 服务地址 |
| `alerter.serverAPIKey` | —(必填) | 用于与 SaaS 端认证的 API Key |
| `alerter.serverTimeout` | `30s` | 单次推送请求的超时时间 |
| `alerter.alertRuleDeliveryWorkers` | `64` | 普通告警规则事件投递的 worker 数量。事件按告警 key 分区到各 worker 队列,同一条告警的事件始终由同一个 worker 串行投递 |
| `alerter.alertRuleEventQueueSize` | `2048` | 每个投递 worker 的事件队列容量 |
| `alerter.alertRuleEventBatchSize` | `200` | 单次批量投递的事件条数上限,最大 200。队列中的事件会攒批发送,满一批或暂时无新事件时即投递 |
| `alerter.alertRuleDeliveryResponseBytes` | `8MB` | 投递接口响应体的大小上限,超出后本次请求按失败处理 |
| `alerter.serverSleep` | `3s` | 批量投递失败后的重试退避初始间隔,每次失败后翻倍,最大 30 秒 |
普通告警规则的 firing / repeat / recovery 事件由批量投递服务(alertruledelivery)发送到 SaaS 端 `POST /monit/api/edge/alert-rule/v1/events` 接口:事件先进入各 worker 的队列,再按批次合并发送,单批不超过 200 条事件且不超过 4 MB。
**重试策略说明**:批量投递采用指数退避重试——首次失败后等待 `alerter.serverSleep`(默认 3 秒),之后每次失败等待时间翻倍,最大 30 秒,重试没有次数上限,直到投递成功或引擎实例关闭。相比旧的固定间隔重试,指数退避能在网络短暂拥塞时避免高频无效重试。
早期版本通过 `alerter.serverConcurrency` 和 `alerter.serverRetry` 控制一个内部内存队列的并发消费(固定间隔、有限次数重试)。该消费者已不再启动,普通告警规则的投递已切换到上述批量投递服务,这两个参数不再生效,无需配置。
**调优建议**:
* **高吞吐场景**(规则数量多、告警频率高):可适当提高 `alerter.alertRuleDeliveryWorkers`(例如 128),减少事件在队列中的积压时间;必要时同步提高 `alerter.alertRuleEventQueueSize`。
* **网络或 CPU 受限场景**:可适当降低 `alerter.alertRuleDeliveryWorkers`(例如 16–32),避免并发出站连接过多影响其他业务流量。
* **网络质量差、丢包率高的场景**:可适当增大 `alerter.serverSleep`(例如 10s),让退避从更长的初始间隔开始,减少拥塞期间的无效请求。
# 引擎失联告警
Source: https://docs.flashduty.com/zh/monitors/engine/engine-lost-alert
配置引擎失联告警规则,在告警引擎挂掉时及时收到通知
告警引擎(`monitedge`)如果挂掉,会导致告警规则无法执行,影响非常大。引擎失联告警功能可以在引擎挂掉时及时发出告警通知,保障监控系统的可靠性。
**菜单入口**:告警引擎 → 引擎失联告警
多个实例组成的引擎集群,只要集群中有一个实例存活,就不会触发引擎失联告警。只有集群中所有实例都失联时才会触发。
## 告警规则列表
列表展示所有已配置的引擎失联告警规则,支持按关键字搜索和自定义显示列。
| 列信息 | 说明 |
| ------------- | --------------------------------- |
| **规则标题** | 告警规则的名称 |
| **告警级别** | Critical(红色)、Warning(橙色)、Info(黄色) |
| **匹配引擎名字** | 该规则监控的引擎集群名称模式,支持通配符 `*` |
| **排除引擎名字** | 排除不需要监控的引擎集群名称模式 |
| **失联时长(秒)** | 引擎集群无心跳超过该时长后触发告警 |
| **发给协作空间** | 告警事件投递到的协作空间 |
| **事件生成次数** | 失联期间最多生成的告警事件次数 |
| **事件生成频率(秒)** | 重复生成告警事件的时间间隔 |
| **启用** | 规则的启用/禁用开关 |
## 新建告警规则
点击**新增**按钮,在侧边抽屉中配置以下参数:
| 配置项 | 说明 | 默认值 |
| -------- | ------------ | ---------------- |
| **规则标题** | 规则名称,用于标识和搜索 | `monitedge lost` |
| **启用** | 是否立即启用该规则 | 启用 |
选择告警事件的严重程度:
* **Critical**:紧急,通常用于核心引擎
* **Warning**:警告,默认级别
* **Info**:信息级别
| 配置项 | 说明 | 默认值 |
| ---------- | -------------------------------- | --- |
| **匹配引擎名字** | 输入需要监控的引擎集群名称模式,支持多个值,`*` 表示匹配所有 | `*` |
| **排除引擎名字** | 输入需要排除的引擎集群名称模式 | 空 |
匹配引擎名字和排除引擎名字不能同时为空。
| 配置项 | 说明 | 默认值 |
| ------------- | --------------------- | --- |
| **失联时长(秒)** | 引擎集群中所有实例失联超过该时长后触发告警 | 120 |
| **事件生成次数** | 引擎持续失联时,最多重复生成多少次告警事件 | 3 |
| **事件生成频率(秒)** | 每次重复生成告警事件的最小时间间隔 | 300 |
选择告警事件要投递到的协作空间。告警事件会通过 Flashduty On-call 的协作空间进行后续的通知分派和处理。
## 编辑和删除
* **编辑**:在列表中点击**编辑**按钮修改规则配置。只有规则创建者、主账号或管理员角色可以编辑。
* **删除**:在列表中点击**删除**按钮。只有规则创建者、主账号或管理员角色可以删除。
* **启用/禁用**:通过列表中的开关快速切换规则状态。
# 实体树
Source: https://docs.flashduty.com/zh/monitors/entity-tree/entity-tree
从 Prometheus 指标标签持续发现实体,使用动态分组和可继承规则统一管理实体告警。
当主机、容器、实例或业务模块持续扩缩容时,逐个维护监控对象和告警规则很容易失效。实体树从 Prometheus 查询结果中自动发现这些动态资源,将它们整理为稳定的实体,并根据标签自动归入不同分组。
你可以在上层分组配置通用告警规则,让规则自动作用于匹配的后代实体;当某个环境或业务需要不同阈值时,只需在对应分组覆盖参数。这样既能减少重复规则,也能让告警策略跟随实体变化。
当前版本以实体告警为主要使用场景。实体树先建立统一、稳定的实体视图,也为后续围绕实体查看指标和分析上下文提供一致入口。
## 适用场景
实体树适合以下场景:
* Kubernetes Pod、云主机、数据库实例等对象频繁创建、销毁或变化
* 多个环境或业务使用相同指标,但告警阈值不同
* 你希望按区域、环境、集群、团队或服务等标签自动管理告警范围
* 多个 Prometheus 数据源需要复用同一套实体定义和告警策略
如果监控对象固定、每条规则只对应一个明确查询,继续使用普通告警规则通常更直接。
## 实体树如何组织监控
| 概念 | 作用 | 示例 |
| ---------- | ----------------------------------------- | ---------------------- |
| **实体类别** | 定义从哪些数据源、通过什么查询发现一类实体,以及哪些标签可以稳定标识实体 | 节点、Pod、数据库实例 |
| **实体** | 一条持续被发现的具体资源。同一数据源内,身份标签值相同的查询结果会归并到同一个实体 | instance=10.0.0.8:9100 |
| **动态分组** | 使用实体标签自动划分范围。实体属性变化后,所属分组会随之更新 | 生产环境、支付服务、华东区域 |
| **实体告警规则** | 在某个分组创建并自动作用于匹配的后代实体 | 节点 CPU 使用率过高 |
| **规则覆盖** | 在子分组调整继承规则的告警级别、参数或连续命中次数 | 生产环境阈值 90%,测试环境阈值 95% |
同一组身份标签值在不同数据源中会形成不同实体。你可以在工作区切换数据源,分别查看实体、规则执行结果和活跃告警。
## 使用前准备
开始前,请确认:
* 当前租户已启用 Monitors,并已部署告警引擎
* 已创建至少一个 Prometheus 数据源
* 你的账号拥有实体树查看权限;创建或修改配置还需要实体树管理权限和相应实体类别或分组的管理权限
* 告警引擎版本满足实体树页面提示的要求
如果告警引擎版本不兼容,页面会提示升级,实体和实体告警状态可能暂时不可用。普通告警规则不受影响。
## 配置实体树
### 1. 申请开通
进入 **Monitors > 实体树**。如果当前租户尚未开通,点击 **申请开通**。申请提交后,页面会显示申请时间;审核通过后即可开始配置。
### 2. 创建实体类别
实体类别决定系统如何发现并识别一类资源。点击 **创建实体类别**,完成以下配置:
| 配置项 | 说明 |
| ------------- | --------------------------------------------- |
| **名称** | 使用用户容易理解的资源类别名称,例如“节点”或“数据库实例” |
| **管理团队** | 选择后,该团队成员可以管理该实体类别及其全部分组;不选择时,仅创建者和租户管理员可以管理 |
| **数据源(精确匹配)** | 按数据源 ID 选择,不受数据源改名影响 |
| **数据源(名称通配)** | 使用名称模式自动匹配数据源,支持 \*、? 和字符范围。适合自动纳入命名规范一致的新数据源 |
| **发现 PromQL** | 返回待发现实体的即时向量。查询结果中的标签会成为实体的候选属性 |
| **身份标签** | 一个或多个稳定标签,共同唯一标识实体 |
| **多值标签** | 可选。同一实体对应多条结果时,将指定标签的非空值合并为集合 |
| **同步周期** | 重新发现实体的间隔,默认 15 秒 |
| **失联保留时间** | 实体暂时从一次成功的发现结果中消失后,继续保留状态的时间,最少 3600 秒 |
精确匹配和名称通配可以同时使用,系统会使用两者匹配到的全部数据源。至少配置一种匹配方式。
例如,以下查询可以发现带有 instance 标签的节点:
```promql theme={null}
up{job="node"}
```
填写查询后,点击 **预览**,再从查询结果中选择身份标签。预览会帮助你检查:
* 每条结果是否都包含身份标签
* 同一身份是否出现普通单值标签冲突
* 多条结果会如何按身份合并
选择长期稳定、能唯一定位资源的标签作为身份标签,例如 instance、pod\_uid 或数据库实例 ID。不要使用会频繁变化的状态、版本或发布批次标签,否则同一资源可能被识别为新实体。
如果一个实体天然对应多个属性值,例如同一节点属于多个业务组,可以将相应标签配置为多值标签。多值标签不能同时作为身份标签。
### 3. 创建动态分组
创建实体类别后,页面左侧会显示实体类别和分组树。在目标节点的操作菜单中选择 **创建子分组**,并使用标签条件定义实体范围。
| 操作符 | 含义 |
| --- | -------------------- |
| = | 标签值相等;值留空时匹配标签缺失或没有值 |
| != | 标签值不等;值留空时匹配至少有一个值 |
| =\~ | 标签值匹配正则表达式 |
| !\~ | 标签值不匹配正则表达式 |
同一分组中的多个条件必须全部满足。子分组还会继承全部上级分组的条件。
例如,你可以先创建 env = prod 的“生产环境”分组,再在其下创建 service = payment 的“支付服务”分组。第二个分组最终只包含同时满足两个条件的实体。
实体可以同时命中多个同级分组。请让同级分组表达清晰、互不冲突的管理维度,并在配置不同规则覆盖时检查最终告警范围。
### 4. 创建实体告警规则
选择要承载规则的分组,打开 **规则** 标签页,然后点击 **创建规则**。
| 配置项 | 说明 |
| ---------- | ------------------------------------------ |
| **规则名称** | 告警名称,支持使用页面提供的模板变量 |
| **PromQL** | 用于判断告警条件的查询。可使用参数占位符,让不同告警级别或分组复用同一查询 |
| **告警级别** | 可分别启用 Critical、Warning 和 Info,并配置参数与连续命中次数 |
| **恢复方式** | 选择“条件不再命中”,或使用独立恢复 PromQL |
| **连续恢复次数** | 连续满足恢复条件多少次后恢复告警 |
| **高级配置** | 配置执行周期、时区、执行延迟和重复通知 |
| **标签与注解** | 为告警补充路由标签和说明;规则名称与注解支持模板变量 |
规则创建在当前分组,并自动作用于当前分组和所有匹配的后代实体。规则列表会分别展示 **本组规则** 和 **继承规则**,帮助你判断规则来自哪个层级。
在 PromQL 中定义一个可复用的 threshold 参数,然后为 Critical、Warning 和 Info 填写不同的参数值。这样只需维护一条查询,就能表达多个告警级别。
### 5. 导入告警规则
除了逐条创建,你还可以在分组的 **规则** 标签页点击 **导入规则**,上传 YAML 文件批量导入到当前分组。系统会自动识别三种来源格式:
| 来源格式 | 说明 |
| ----------------------- | --------------------------------------------------------------- |
| **Entity Alert 规则包** | 从其他分组或租户导出的规则包,保留完整规则配置。规则包记录的身份标签必须与目标实体类别一致,否则无法导入 |
| **Prometheus Rules** | 标准 Prometheus 告警规则文件(`groups` 列表、`rules` 列表或单条规则),导入时按下文的转换规则处理 |
| **Prometheus Operator** | PrometheusRule CRD(`spec.groups`),转换方式与 Prometheus Rules 相同 |
限制与要求:
* 一次只能上传一个不超过 1 MB 的 `.yaml` 或 `.yml` 文件,单次最多导入 100 条规则
* 不支持 recording rule(只定义 `record` 的规则会被忽略);同一条规则不能同时配置 `alert` 和 `record`
* 规则标签的值不能包含 `{{ }}` 动态模板;PromQL 必须返回瞬时向量,比较表达式不能使用 `bool` 修饰符
* 从 Prometheus 格式导入时,PromQL 的每条结果都必须包含目标实体的身份标签,否则告警无法关联到实体
上传后系统会先执行 **预检**,逐条展示转换结果和名称冲突,不会立即写入。每条规则会被标记为以下状态之一:
| 预检状态 | 含义 |
| -------- | -------------------------------------- |
| **可导入** | 校验通过,可以写入 |
| **创建副本** | 与当前分组已有规则同名,将使用带序号的新名称创建 |
| **跳过** | 与当前分组已有规则同名,按所选策略保留现有规则 |
| **已忽略** | recording rule 等不支持的规则,不会导入 |
| **校验失败** | 缺少 `alert` 或 `expr`、PromQL 不合法等问题,无法导入 |
上传文件后可以选择 **同名规则处理方式**:**跳过同名规则**(默认,保留目标分组中的现有规则)或 **创建副本**(自动使用带序号的新名称),切换后预检会自动重新执行。Entity Alert 规则包采用严格校验,只要存在校验失败的规则就无法提交导入;Prometheus 格式允许略过失败条目,仅导入可导入的规则。
从 Prometheus 格式导入时,系统按以下规则转换,并在预检结果中标注降级项:
* `labels.severity` 映射告警级别:`page`、`p1`、`error`、`critical` 转为 Critical,`info` 转为 Info,其余取值转为 Warning;使用 `{{ }}` 动态取值的 severity 统一按 Warning 转换
* 未提供 `interval` 时执行周期默认 1 分钟;`for` 折算为连续命中次数,`keep_firing_for` 折算为连续恢复次数
* 与实体身份标签同名的规则标签会被忽略,避免干扰实体识别
为避免导入后立即产生告警,所有导入规则都会保持 **停用**,并自动在规则列表中选中。请检查转换结果后,再通过批量启用让规则生效。
### 6. 覆盖继承规则
如果子分组需要不同阈值,在子分组的 **继承规则** 列表中选择 **覆盖继承规则**。你可以调整:
* 告警级别是否继承、启用或停用
* 各告警级别的参数和连续命中次数
* 恢复查询参数和连续恢复次数
查询文本、执行周期、恢复方式和重复通知继续继承上级规则。如果这些执行方式也需要不同,请在当前分组新建一条规则。
保存覆盖配置前,页面会展示最终生效配置和查询预览。清除覆盖后,当前分组会恢复使用上级配置。
### 7. 批量管理规则
在本组的 **规则** 标签页勾选本组规则后,可以执行批量操作,单次最多选择 100 条:
* **批量启用 / 批量停用**:确认后统一变更启用状态。批量停用会异步关闭相关活跃告警,重新启用不会恢复已关闭的告警
* **导出规则**:将选中的规则导出为 Entity Alert 规则包(`entity-alert-rules.yaml`),单次最多导出 100 条。导出的规则包可以在其他分组或租户通过 **导入规则** 重新导入,形成完整的迁移路径
规则列表中的 **启用状态** 开关可以单独启用或停用一条规则;停用前需要确认,相关活跃告警会异步关闭。
勾选、批量启停、导入和导出都需要实体树管理权限和当前分组的管理权限。没有管理权限的规则不能参与批量启停,但仍可随选中规则一起导出。
## 通过链接直达规则
实体树支持通过 URL 参数从外部链接直达某条实体告警规则。例如在告警详情等页面看到某条实体告警时,可以携带链接跳转到实体树,直接调整产生告警的规则。在实体树页面 URL 后附加以下参数:
```text theme={null}
?tab=rules&account_id=<租户 ID>&definition_id=<实体类别 ID>&datasource_id=<数据源 ID>&group_id=<分组 ID>&rule_id=<规则 ID>&open=edit
```
跳转成功后,页面会自动:
* 切换到 **规则** 标签页,自动选中链接指定的实体类别、分组和数据源,并展开对应分组
* 自动打开目标规则的抽屉:规则属于当前分组的打开**编辑**抽屉,规则继承自上级分组的打开**覆盖**抽屉
如果链接无法生效,页面会给出对应错误提示:
* 链接中的租户 ID 与当前登录组织不一致:提示切换组织后重试
* 实体类别、分组、数据源或规则不存在(例如规则已被删除):提示无法定位告警规则
* 当前账号没有实体树管理权限或对应分组的规则管理权限:不打开抽屉,提示没有规则管理权限
URL 中的各 ID 均为正整数。参数缺失、非法或未携带 `open=edit` 时,链接不会生效,页面按普通方式打开。
## 规则名称与注解模板变量
规则名称和注解支持 Go `text/template` 语法。模板在告警引擎侧、每次产生告警事件时渲染,可以引用当次评估的标签、数值和实体上下文。渲染失败时,对应字段会显示 ``,你可以在规则的执行错误摘要中查看原因。
### 内置变量
| 变量 | 类型 | 说明 |
| -------------- | ------------------- | ---------------------------------------------------------------------- |
| `$labels` | `map[string]string` | 告警标签。用 `$labels.` 或 `index $labels ""` 读取单个标签,标签不存在时返回空字符串 |
| `$value` | `float64` | 当次评估的告警值 |
| `.Labels` | `map[string]any` | 与 `$labels` 相同 |
| `.Value` | `float64` | 与 `$value` 相同 |
| `.EntityAlert` | `map[string]any` | 实体告警上下文,可用字段见下表 |
### `.EntityAlert` 字段
| 字段 | 说明 |
| --------------------------------------------------------------------------- | --------------------------------------------------------------- |
| `.EntityAlert.entity_key` | 实体标识 |
| `.EntityAlert.entity_definition_id` / `.EntityAlert.entity_definition_name` | 实体类别 ID 和名称 |
| `.EntityAlert.rule_id` | 规则 ID |
| `.EntityAlert.name` | 渲染后的规则名称,仅注解模板可用,规则名称不能引用自身 |
| `.EntityAlert.event_kind` | 事件类型:`firing`、`severity_changed`、`repeat`、`recovery` 或 `closed` |
| `.EntityAlert.value` | 当次评估的告警值,与 `$value` 相同 |
| `.EntityAlert.promql` | 实际生效的告警 PromQL |
| `.EntityAlert.recovery_promql` | 实际生效的恢复 PromQL;未配置独立恢复查询时为空 |
| `.EntityAlert.query_at_ms` | 查询时间,Unix 毫秒时间戳 |
| `.EntityAlert.policy_scope_group_id` | 实际生效策略所在的分组 ID |
| `.EntityAlert.account_id` | 租户 ID |
| `.EntityAlert.data_source_name` / `.EntityAlert.data_source_type` | 数据源名称和类型 |
| `.EntityAlert.entity_multi_value_fields` | 多值标签的取值集合 |
多值标签在 `.EntityAlert.entity_multi_value_fields` 中以集合形式提供,可配合 `first`、`last`、`has`、`join` 函数读取:
```gotemplate theme={null}
{{ join "," (index .EntityAlert.entity_multi_value_fields "biz_group") }}
```
规则名称示例:
```gotemplate theme={null}
节点 {{ $labels.instance }} CPU 使用率 {{ printf "%.1f" $value }}%
```
注解示例(每个注解字段单独是一段模板):
```gotemplate theme={null}
https://example.com/runbooks/node-cpu?entity={{ .EntityAlert.entity_key }}
```
## 查看实体和告警
选择实体类别、分组和数据源后,工作区提供三个标签页:
| 标签页 | 可以查看的内容 |
| -------- | --------------------------------------------- |
| **实体** | 当前分组中的实体标识、状态、标签、归属分组和最近发现时间。可按状态、实体标识前缀或标签筛选 |
| **规则** | 本组规则、继承规则、启用状态、最近评估时间、命中的实体和告警数量。可查看执行历史和错误摘要 |
| **活跃告警** | 告警级别、名称、实体标识、告警维度、实际生效的策略分组、当前值和触发时间 |
点击活跃告警的 **查看详情**,可以进一步确认实体来源、规则、告警维度、标签和通知情况。排障时先确认页面顶部的数据源和当前分组,再检查规则的来源分组与实际策略范围。
## 理解失联保留
实体可能因抓取抖动、短暂网络故障或滚动发布,从一次成功的发现结果中暂时消失。失联保留期间:
* 实体状态显示为 **失联保留**
* 系统暂停该实体的告警判断、恢复判断和重复通知
* 实体重新出现时会延续原有告警状态
* 超过保留时间仍未出现时,相关活跃告警会结束
失联保留时间至少为 3600 秒。请根据资源的正常重建周期设置,不要用过短时间放大瞬时抖动。
## 配置变更注意事项
以下操作会改变实体身份、分组范围或告警生命周期:
* **修改身份标签**:页面会先预览身份迁移及恢复查询的影响。确认后,旧身份关联的活跃告警会结束,新身份会重新发现
* **修改多值标签**:实体会重新分类,相关告警会按新配置重新评估
* **修改分组条件或规则覆盖**:实体的有效范围或策略可能变化,当前告警可能结束并按新配置重新评估
* **修改本组规则**:保存前页面会预览本次修改对后代节点覆盖配置的影响,并列出受影响的覆盖数量。如果修改导致部分级别覆盖或参数覆盖失效,对话框会要求你确认后永久清理;清理后的覆盖配置无法恢复
* **停用或删除规则**:相关活跃告警会异步结束;重新启用不会恢复已经结束的告警
* **删除实体类别或分组**:必须先清理页面提示的依赖项,受影响的活跃告警会异步结束
在生产环境修改身份标签、分组条件或继承覆盖前,先使用页面提供的预览确认影响,并选择业务低峰期操作。
## 最佳实践
* 为实体类别选择稳定的身份标签,并在上线前用多个数据源预览
* 按“环境 → 区域 → 业务”等稳定维度设计分组,避免复制组织架构中的临时层级
* 把通用规则放在较高层级,只在确有差异的子分组覆盖阈值
* 需要不同查询或调度时新建规则,不要把一条继承规则改造成过多例外
* 定期查看规则最近评估、执行历史和活跃告警,及时处理数据源或告警引擎版本问题
# Flashduty Monitors 常见问题
Source: https://docs.flashduty.com/zh/monitors/faq/faq
Monitors 常见问题解答
在告警规则的列表页面,有一个**调试日志开关**,您可以打开这个开关,之后告警引擎进程 `monitedge` 会输出该规则的详细执行日志,方便您排查问题。
`monitedge` 会把日志输出到标准输出(`stdout`),查看方式取决于部署方式:
| 部署方式 | 查看日志命令 |
| --------------- | ------------------------------------------------------------ |
| Docker | `docker logs ` |
| Kubernetes | `kubectl logs ` |
| Linux (systemd) | `journalctl -u monitedge.service -f` 或查看 `/var/log/messages` |
`monitedge` 遵照云原生最佳实践,把日志输出到标准输出,不会写到单独的日志文件中,以方便日志收集系统采集,也方便轮转和压缩。
**菜单入口**:概览
概览页面提供告警规则的全局视图,由以下卡片组成:
| 卡片名称 | 说明 |
| ----------------- | -------------------------------------------------------------- |
| **告警规则总量历史趋势图** | 面积图展示告警规则总数随时间的变化趋势,横轴为日期,纵轴为规则数量,帮助您掌握规则增长或缩减的整体走势 |
| **各协作空间告警规则数量对比** | 饼图展示各协作空间关联的告警规则数量分布。默认显示 Top 10 的协作空间,超出部分汇总为"其他",可点击展开查看全部详情 |
| **系统事件列表** | 展示告警引擎产生的系统事件(如引擎失联、配置异常等),支持分页浏览和删除操作,帮助您及时发现并处理基础设施层面的问题 |
概览页面顶部会检查您是否已安装告警引擎。如果尚未安装,系统会显示引导提示,引导您前往告警引擎页面完成安装。
在告警规则的编辑页面或详情页面,你可以找到**克隆**操作按钮。点击后会基于当前规则的配置创建一条新规则,所有配置项会被复制过来(名称除外),方便你快速创建相似的告警规则。
在创建或编辑告警规则时,配置好查询条件后,可以点击**查询预览**按钮。系统会立即执行一次查询并展示结果,帮助你验证查询表达式是否正确、返回的数据是否符合预期,无需等到下一个检测周期。
备注描述支持 Markdown 格式,你可以使用标题、列表、链接、代码块等 Markdown 语法来组织内容。同时支持引用变量,将告警事件的标签值、查询结果等动态信息嵌入到备注中,方便值班人员快速了解告警上下文。
# 文件夹管理
Source: https://docs.flashduty.com/zh/monitors/folders/folders
使用树形文件夹结构组织告警规则,支持团队级别的访问控制
Monitors 使用树形文件夹结构来组织和管理告警规则。每条告警规则都必须归属于某个文件夹,你可以通过层级结构进行分类管理,并为不同层级配置团队访问权限。
**菜单入口**:告警规则(左侧树形导航)
## 文件夹树
页面左侧展示文件夹树形结构。你可以:
* **新建文件夹**:在树中创建子文件夹
* **选择文件夹**:点击文件夹查看其详情和所属的告警规则
* **层级嵌套**:支持多级嵌套,满足复杂的组织结构需求
## 文件夹详情
选中文件夹后,右侧展示该文件夹的详细信息:
| 属性 | 说明 |
| -------- | ------------------------ |
| **名称** | 文件夹名称,有权限的用户可点击编辑图标修改 |
| **备注** | 文件夹的补充说明,有权限的用户可点击编辑图标修改 |
| **更新者** | 最后修改该文件夹的用户 |
| **创建者** | 创建该文件夹的用户 |
| **更新时间** | 最后修改时间 |
| **创建时间** | 创建时间 |
## 团队访问控制
文件夹支持基于团队的访问控制,通过为文件夹绑定团队来限制操作权限。
### 权限继承
文件夹详情下方的**权限继承**表格展示从当前文件夹到根节点的完整路径,以及每个层级绑定的团队。
| 列信息 | 说明 |
| -------- | ------------------------ |
| **节点路径** | 从根节点到当前节点的完整路径 |
| **关联团队** | 该层级绑定的团队,有权限的用户可点击编辑图标修改 |
### 权限判定规则
系统按以下规则判定用户是否有操作权限:
1. **主账号**始终拥有所有文件夹的操作权限
2. 如果当前文件夹或其任何父级文件夹绑定了团队,用户必须属于对应团队才有权限
3. 如果文件夹链路上没有绑定任何团队,所有用户都可以操作
建议为顶层文件夹绑定团队,子文件夹会自然继承访问范围。这样可以实现按部门或按项目划分告警规则的管理权限。
# Flashduty Monitors 入门指南
Source: https://docs.flashduty.com/zh/monitors/quickstart/quickstart
Monitors 快速开始指南,帮助您快速上手告警功能
要体验 Monitors 功能,核心包含三个步骤:
部署告警引擎到私有网络
配置要监控的数据来源
定义告警条件和通知方式
## 安装 monitedge
`monitedge` 需要部署在用户私有网络内,负责从 SaaS 同步告警规则,周期性查询数据源并进行阈值判定,产生告警事件并推送给 SaaS 端。
**菜单入口**:告警引擎 → 引擎安装/升级
支持 Linux、Docker、Kubernetes 三种安装方式。
**引擎集群名字**非常重要:相同名字的 `monitedge` 会组成一个集群,共同分片处理告警规则,避免单点故障。
* 单套集群:保持默认的 `default` 即可
* 多套集群(如美东机房、华南机房各一套):请为每套集群指定不同的名字

### 告警引擎状态
`monitedge` 安装完成后,会自动连接 SaaS 端并周期性同步告警规则。您可以在告警引擎状态页面查看当前状态信息。
长期没有心跳的引擎实例会展示删除按钮,可点击移除以避免引擎失联告警。
### 引擎失联告警
`monitedge` 挂掉影响很大,因此提供引擎失联告警。
多个实例组成的引擎集群,只要集群中有一个实例存活,就不会触发引擎失联告警。
## 创建数据源
**菜单入口**:数据源 → 新建

| 配置项 | 说明 |
| ----------- | --------------------------------------------- |
| **关联告警引擎** | 指定该数据源由哪个告警引擎集群进行数据查询和告警判定,通常选择同机房的集群 |
| **数据源连接地址** | 给 `monitedge` 连接的地址,必须是 `monitedge` 能访问到的内网地址 |
## 创建告警规则
**菜单入口**:告警规则
告警规则可能会很多,Monitors 提供树形分组结构进行分类管理。每个告警规则都要属于某个分组,您可以先创建分组,再在分组下创建告警规则。
### 基础配置

| 配置项 | 说明 |
| -------- | ----------------------------------------------------------------------- |
| **规则名称** | 告警规则的名称,不支持引用变量(固定名称便于过滤、聚合操作)。同一分组内必须唯一;导入、编辑或移动规则时如与目标分组中已有规则重名,操作会失败 |
| **附加标签** | 类似 Prometheus 中的 `labels`,会附加到所有告警事件上,便于过滤、路由、抑制 |
### 数据源选择

先选择 **数据源类型**。这里只会列出**已经配置过至少一个数据源**的类型——没有配置过的类型不会出现,避免你选中一个查不到任何数据源的类型。编辑一条已有规则时,它当前使用的类型始终可见,即使该类型下的数据源后来被删光了。
如果列表为空(提示「暂无可用数据源」),说明当前账户还没有配置任何数据源,可以点击 **前往数据源管理页面** 先创建;如果只是当前选中的类型没有可用数据源,页面会提示「当前数据源类型暂无可用数据源,请先创建数据源或切换类型」。类型列表加载失败时会显示 **重新加载** 按钮。
选定类型后,Monitors 支持一个规则生效到多个数据源,提供两种绑定方式:
* **名称通配**:通过通配符匹配数据源名称。`*` 匹配所有数据源,`db-*` 匹配所有以 `db-` 开头的数据源。存储的是名称字符串,数据源改名会影响匹配。
* **精确匹配**:从下拉列表中按 ID 选择具体数据源,不受数据源改名影响。
两种方式可以同时使用,至少需要填写一种。规则会生效到两种方式匹配到的所有数据源。
如果对规则绑定的稳定性要求高(避免数据源改名导致规则失效),建议使用精确匹配。详情参见[数据源管理](/zh/monitors/data-sources/data-sources)。
### 查询检测方式

配置如何查询数据源及如何判定告警条件。请阅读页面上 **查询检测方式** 右侧的使用说明。
### 检测频率与生效时间

| 配置项 | 说明 |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **检测频率** | 通常是周期性检测,也支持 `cron` 表达式(精确到秒)和 `@every` 快捷写法 |
| **查询时间偏移** | 设置查询时间偏移量(秒),用于处理数据源存在采集延迟的场景。例如设置为 60,则查询窗口整体向前偏移 60 秒,确保数据已完成写入后再查询。仅适用于 Prometheus、Loki、VictoriaLogs、SLS 数据源 |
| **规则时区** | 告警规则的执行时区,决定 `cron` 调度时间和**生效时间**窗口的解释方式。默认 `Asia/Shanghai`,必须填写有效的 IANA 时区名(如 `Asia/Shanghai`、`UTC`、`Europe/London`、`America/New_York`) |
| **生效时间** | 告警规则的生效时间段,非生效时间段内不会触发告警;时间窗口按上面配置的**规则时区**计算 |
**时区填写规则**:
* **规则时区**只接受 IANA 标准时区名。`Local`、`UTC+8`、`CST`、`GMT+8` 等简写或偏移量写法会被拒绝
* **`cron` 表达式不能以 `CRON_TZ=` 或 `TZ=` 开头**。如果您从开源 cron 系统迁移过来并习惯把时区内嵌在 cron 字符串里(例如 `CRON_TZ=Asia/Shanghai 0 0 * * *`),请去掉前缀,把时区填到**规则时区**字段中
**cron 表达式格式规则**:
* `cron` 表达式必须是 **6 段秒级表达式**,顺序为秒、分、时、日、月、周。5 段写法(例如 `*/5 * * * *`)会被拒绝,需要补充秒字段(例如 `0 */5 * * * *`)
* 支持 `@every` 快捷写法,例如 `@every 30s`,表示每 30 秒检测一次。时长必须是**不小于 1 秒的整数秒**,支持 `@every 1m30s` 这类组合时长;`@every 0s`、`@every 1500ms` 等亚秒或不满足整秒的写法会被拒绝
* 修改已有规则时同样会校验检测频率,历史上保存的不合规表达式需要先修正才能保存
规则保存时还会校验运行时配置:重复通知的**最大次数**(`repeat_total`)和**重复间隔**(`repeat_interval`),以及各检测模式(阈值、数据存在、数据缺失)的**连续命中次数**和**连续恢复次数**都必须 ≥ 1。校验失败的规则不会被调度执行,告警引擎会将失败原因上报为 `alert-rule-schedule-invalid` 问题,请根据错误信息修正规则配置。
### 事件配置
| 配置项 | 说明 |
| --------- | --------------------------------------------------- |
| **自定义字段** | 类似 Prometheus 中的 `annotations`,可附加仪表盘 URL、SOP URL 等 |
| **关联查询** | 不作为阈值判定依据,但可放到备注中作为变量引用(如附加日志样例) |
| **备注描述** | 非结构化文本字段,支持引用变量,便于值班人员快速定位问题 |
| **协作空间** | 指定 Flashduty On-call 中的协作空间,不指定则根据集成路由规则投递 |
| **重复通知** | 告警未恢复时持续通知,可配置间隔和最大次数(默认 10000 次) |
最大通知次数并不代表终端用户收到的消息提醒次数。因为 Monitors 产生的告警事件会投递到 On-call,可能会被聚合降噪,最终发送次数取决于 On-call 配置。
## 查看效果
完成配置后,如果告警条件触发,告警规则前的状态会变成 `Triggered`。

告警规则列表的搜索框支持按规则名称、规则 ID 或标签进行搜索过滤,方便快速定位规则。也可以通过 URL 参数 `?rule_id=` 直接跳转到指定规则。
点击 `Triggered` 可以看到该规则产生的告警事件(也可到 On-call 中查看):

点击告警事件标题,可查看详情,分为三个标签页:**告警概览**、**时间线**、**关联事件**。
## 批量操作
告警规则列表支持多选后进行批量操作,提升规则管理效率。
### 批量启用/禁用/删除
在列表中勾选多条规则后,可以一键批量启用、批量禁用或批量删除。
### 批量编辑字段
勾选多条规则后点击**批量更新**,可以统一修改以下 10 个字段:
| 可批量编辑的字段 | 说明 |
| ---------- | -------------------------------------------------------------------------------- |
| **附加标签** | 统一设置 labels |
| **数据源** | 统一切换数据源 |
| **检测频率** | 统一调整检测周期 |
| **规则时区** | 统一切换告警规则的 IANA 时区 |
| **生效时间** | 统一配置生效时间段 |
| **查询时间偏移** | 统一设置查询时间偏移。仅当所有选中规则的数据源都支持查询时间偏移(Prometheus、Loki、VictoriaLogs、SLS)时才可批量更新,否则该项禁用 |
| **自定义字段** | 统一配置 annotations |
| **协作空间** | 统一指定告警投递的协作空间 |
| **重复发送配置** | 统一设置重复通知间隔和次数 |
| **调试日志** | 统一开启或关闭调试日志 |
操作方式:在批量更新面板中先选择要修改的字段,然后设置新值,点击确定即可批量应用到所有选中规则。
### 批量移动
勾选多条规则后,可以将它们批量移动到其他文件夹中。
## 导入告警规则
Monitors 支持三种导入模式,你可以根据来源选择最合适的方式。
**菜单入口**:告警规则 → 导入
### 从规则库导入
选择**规则库**模式,可以从[规则库](/zh/monitors/rule-repository/rule-repository)中选择已有的规则模板进行导入。导入时需要指定告警事件投递的协作空间。
### 从 JSON 导入
选择 **Flashduty Rules JSON** 模式,粘贴 JSON 格式的告警规则数组。该格式与导出功能产生的 JSON 格式一致,适合跨租户或跨环境迁移告警规则。导入时需要指定协作空间。
JSON 内容必须是数组格式(以 `[` 开头),每个元素是一条完整的告警规则定义。
### 从 Prometheus YAML 导入
选择 **Prometheus Rules YAML** 模式,粘贴标准的 Prometheus 告警规则 YAML 内容。

要求以 `groups` 为根节点的标准格式。YAML 缩进必须正确,否则会导入失败。每条规则需要包含 `alert` 和 `expr` 字段。
### 导入结果
如果部分规则导入失败,系统会弹出导入结果表格,展示每条规则的导入状态和错误信息。全部成功时直接提示导入成功。
## 导出告警规则
在列表中勾选需要导出的规则,点击**导出**按钮。系统以 JSON 格式展示所选规则的完整配置,你可以:
* **下载**:将 JSON 保存为 `monit.json` 文件
* **复制**:将 JSON 内容复制到剪贴板
导出的 JSON 可用于备份,也可以通过 JSON 导入模式导入到其他环境。
## 规则变更记录
每条告警规则都有完整的变更审计记录。你可以在规则详情中查看**变更记录**,了解规则的历史修改情况。
### 查看变更记录
变更记录列表展示每次操作的以下信息:
| 列信息 | 说明 |
| -------- | ------- |
| **操作时间** | 变更发生的时间 |
| **操作类型** | 如创建、更新等 |
| **操作人** | 执行变更的用户 |
### 版本对比
在变更记录列表中勾选两条记录,点击**对比**按钮,系统会以 JSON diff 的方式展示两个版本之间的差异,帮助你快速了解具体修改了哪些配置项。
# 规则库
Source: https://docs.flashduty.com/zh/monitors/rule-repository/rule-repository
浏览和管理告警规则模板,支持按数据源类型分类、共享和导入
规则库提供了一套告警规则模板管理机制,你可以将常用的告警规则保存为模板,方便团队复用和快速导入到告警规则列表中。
**菜单入口**:规则库
## 按数据源类型浏览
规则库首页以卡片形式展示所有可用的数据源类型。点击某个数据源类型(如 Prometheus、MySQL 等)即可查看该类型下的所有规则模板。
你可以通过搜索框按名称过滤数据源类型。
## 规则模板列表
点击数据源类型后,侧边抽屉展示该类型下的规则模板列表,包含以下信息:
| 列信息 | 说明 |
| -------- | ---------- |
| **描述** | 规则模板的说明文本 |
| **可见范围** | 私有、租户可见或公开 |
| **贡献者** | 创建者信息和更新时间 |
支持按描述内容搜索。
## 创建规则模板
在规则模板列表中点击**新建规则集**按钮。
| 配置项 | 说明 |
| -------- | --------------------- |
| **描述** | 规则模板的说明文本 |
| **可见范围** | 控制谁可以看到和使用该模板 |
| **规则内容** | 以 JSON 格式定义告警规则,支持格式化 |
规则模板支持三种可见范围:
| 可见范围 | 说明 |
| -------- | ------------ |
| **私有** | 仅创建者本人可见 |
| **租户可见** | 同一租户下的所有成员可见 |
| **公开** | 所有用户可见 |
点击**确定**完成创建。
## 编辑和删除
只有规则模板的创建者(或同租户的主账号)可以编辑和删除模板。
* **查看**:点击描述文本或**查看**按钮,查看规则模板的详细内容。
* **编辑**:点击**编辑**按钮修改模板信息。
* **删除**:点击**删除**按钮,确认后删除模板。
## 从规则库导入
在告警规则列表页面,点击**导入**按钮并选择**规则库**模式,即可从规则库中选择模板导入为实际的告警规则。详见[导入告警规则](/zh/monitors/quickstart/quickstart#导入告警规则)。
# 配置监控对象
Source: https://docs.flashduty.com/zh/monitors/targets/configure-targets
配置 agent.yaml,接入主机、MySQL、Redis、PostgreSQL、MongoDB、Kafka 和 Elasticsearch 等监控对象
安装包内会包含一个默认 `agent.yaml`。如果只需要接入主机对象,可以先保持默认配置,确认页面出现主机后再继续增加 MySQL、Redis、PostgreSQL 等对象。
## 基础配置示例
下面是一个适合首次接入的基础配置:
```yaml theme={null}
locator_mappings: {}
host:
sample_interval: 2s
disk:
extra_exclude_mount_points: []
extra_exclude_fs_types: []
statfs_timeout: 1s
top_n: 20
disk_io:
top_n: 5
skip_loop: true
skip_partitions: true
dm_exclude_patterns:
- "docker-*"
- "*-pool"
network_io:
top_n: 5
exclude_patterns:
- "lo"
- "veth*"
- "docker*"
- "br-*"
- "virbr*"
- "flannel*"
- "cali*"
- "cni*"
- "tun*"
- "tap*"
top_processes:
default_top_n: 10
max_top_n: 50
include_cmdline: false
shell_exec:
enabled: true
default_max_lines: 200
cat_max_file_size: 20971520
user_allow_list: []
tool_policy:
disabled_tools: []
mysql: []
redis: []
redis_sentinel: []
postgres: []
mongodb: []
mongodb_mongos: []
kafka: []
elasticsearch: []
```
## locator\_mappings
`locator_mappings` 用于设置页面上展示的对象地址,通常用于 MySQL 等非主机对象。
例如 Agent 连接 MySQL 时使用的是本机地址:
```yaml theme={null}
mysql:
- targets:
- "localhost:3306"
```
但你希望页面上显示为更容易识别的数据库地址,可以这样配置:
```yaml theme={null}
locator_mappings:
"localhost:3306": "db-prod-01.example.com:3306"
```
建议:
* MySQL、Redis、PostgreSQL、MongoDB 等服务如果配置了 `localhost` 或 `127.0.0.1`,建议同时配置 `locator_mappings`。
* 映射后的地址应使用稳定 IP、DNS 或 `host:port`。
* 不建议把映射后的地址写成 `localhost`、`127.0.0.1`。
* Kafka 和 Elasticsearch 是集群级对象,不使用 `locator_mappings`。Kafka 使用 `cluster_name` 作为标识;Elasticsearch 自动从集群获取 `cluster_name`。
## host
`host` 用于调整主机诊断时的采集行为。首次接入一般不需要修改。
| 配置 | 建议值 | 说明 |
| ------------------------------- | ----------- | ----------------------------- |
| `sample_interval` | `2s` 或 `3s` | CPU、磁盘 I/O、网络 I/O 等指标的采样时间。 |
| `disk.statfs_timeout` | `1s` | 避免异常挂载点拖慢诊断。 |
| `disk.top_n` | `20` | 控制返回的文件系统数量。 |
| `disk_io.top_n` | `5` | 控制返回的磁盘 I/O 设备数量。 |
| `network_io.top_n` | `5` | 控制返回的网卡数量。 |
| `top_processes.default_top_n` | `10` | 默认返回的进程数量。 |
| `top_processes.include_cmdline` | `false` | 默认不返回完整命令行,避免泄露密码、token 或连接串。 |
## shell\_exec
`shell_exec` 控制 Agent 是否允许执行受控的主机诊断命令。
```yaml theme={null}
host:
shell_exec:
enabled: true
default_max_lines: 200
cat_max_file_size: 20971520
user_allow_list: []
```
建议:
* 需要 AI-SRE 做主机现场诊断时,保持 `enabled: true`。只有受控的 shell 才能执行,放心开启。
* 命令偶尔被拦截时,可以由本机 root [人工审批该命令](/zh/monitors/targets/install-agent#人工审批被拦截的-shell-命令)。
* 对于需要长期重复使用的命令,确认其安全、只读且不会输出敏感信息后,再将完整命令添加到 `user_allow_list`。
人工审批和 `user_allow_list` 都不能放开关机、重启、破坏系统或读取敏感凭据等高危操作。
如需紧急禁用某个工具,可以使用 `tool_policy.disabled_tools`:
```yaml theme={null}
tool_policy:
disabled_tools:
- shell.exec
```
修改 `shell_exec.enabled` 或 `tool_policy.disabled_tools` 后,发送 SIGHUP reload 即可生效,无需重启 Agent。
## MySQL
如果需要诊断 MySQL,在 `mysql:` 中添加实例配置。推荐使用只读 MySQL 账号,并优先把密码放到独立凭据文件中:
```yaml theme={null}
locator_mappings:
"localhost:3306": "db-prod-01.example.com:3306"
mysql:
- targets:
- "localhost:3306"
connection:
charset: utf8mb4
timeout: 3s
max_open_conns: 8
max_idle_conns: 2
overview:
sample_interval: 2s
query:
enabled: false
default_max_rows: 200
statement_timeout: 6s
credential:
source: env_file
path: /etc/monit-agent/mysql.env
username_key: MYSQL_USER
password_key: MYSQL_PASSWORD
```
凭据文件示例:
```text theme={null}
MYSQL_USER=monit_ro
MYSQL_PASSWORD=
```
| 配置 | 建议 |
| -------------------------- | -------------------------------------------------------------- |
| `targets` | 显式写 `host:port`。如果使用 `localhost:3306`,建议配置 `locator_mappings`。 |
| `connection.timeout` | 建议 `3s`。 |
| `overview.sample_interval` | 建议 `2s` 或 `3s`。 |
| `query.enabled` | 默认 `false`。只有确认账号是只读账号时再开启。 |
| `query.default_max_rows` | 建议 `200`。 |
| `query.statement_timeout` | 建议 `6s`。 |
| `credential.source` | 建议使用 `env_file`。 |
如果启用 `mysql.query`,请务必使用只读账号。这个工具用于执行受控只读 SQL,不适合使用高权限账号。
## Redis
如果需要诊断 Redis,在 `redis:` 中添加实例配置。
| 工具 | 功能 | 默认状态 |
| ---------------- | ---------------------------------------------- | ---- |
| `redis.overview` | 采集两次 INFO ALL 并计算 diff,返回内存、命中率、连接数、QPS 等关键指标。 | 启用 |
| `redis.slowlog` | 读取 SLOWLOG GET 返回近期慢查询记录。 | 启用 |
| `redis.command` | 执行受控只读 Redis 命令(白名单策略)。 | 默认禁用 |
```yaml theme={null}
locator_mappings:
"localhost:6379": "redis-prod-01.example.com:6379"
redis:
- targets:
- "localhost:6379"
connection:
database: 0
timeout: 3s
overview:
sample_interval: 2s
command:
enabled: false
credential:
source: env_file
path: /etc/monit-agent/redis.env
password_key: REDIS_PASSWORD
```
```text theme={null}
REDIS_PASSWORD=
```
| 配置 | 建议 |
| -------------------------- | ---------------------------------------------------------------------------------------- |
| `targets` | 显式写 `host:port`。如果使用 `localhost:6379`,建议配置 `locator_mappings`。 |
| `connection.database` | 默认 `0`。 |
| `connection.timeout` | 建议 `3s`。 |
| `overview.sample_interval` | 建议 `2s` 或 `3s`,范围 `[1s, 5s]`。 |
| `command.enabled` | 默认 `false`。只有确认需要执行受控只读命令时再开启。 |
| `credential` | Redis \< 6 只有密码认证,`username` 可不配置。Redis 6+ ACL 模式下可同时配置 `username_key` 和 `password_key`。 |
`redis.command` 启用后,只允许执行白名单内的只读命令,如 `CONFIG GET`、`CLIENT LIST`、`MEMORY USAGE`、`LATENCY HISTORY` 等。写命令会被拒绝。
## Redis Sentinel
如果需要诊断 Redis Sentinel 高可用集群,在 `redis_sentinel:` 中添加 Sentinel 进程配置。注意 `redis_sentinel` 与 `redis` 是两种不同的对象类型,分别指向 Sentinel 进程和 Redis 数据节点。
| 工具 | 功能 | 默认状态 |
| ------------------------- | ----------------------------------------------------- | ---- |
| `redis_sentinel.overview` | 获取 Sentinel 的 INFO 信息,包含已监控的 master 列表和状态。 | 启用 |
| `redis_sentinel.topology` | 获取所有被监控 master 的拓扑信息,包括 master、replica、sentinel 节点列表。 | 启用 |
```yaml theme={null}
redis_sentinel:
- targets:
- "10.1.2.10:26379"
- "10.1.2.11:26379"
- "10.1.2.12:26379"
connection:
timeout: 3s
credential:
source: env
password_key: REDIS_SENTINEL_PASSWORD
```
| 配置 | 建议 |
| -------------------- | ----------------------------------------------------------------------------- |
| `targets` | Sentinel 默认端口 `26379`,显式写 `host:port`。 |
| `connection.timeout` | 建议 `3s`。 |
| `credential` | Sentinel 通常只有密码认证(无 username)。如果 Sentinel 未启用 `requirepass`,可以不配置 credential。 |
## PostgreSQL
如果需要诊断 PostgreSQL,在 `postgres:` 中添加实例配置。
| 工具 | 功能 | 默认状态 |
| ------------------- | ---------------------------------------------- | ---- |
| `postgres.overview` | 采集两次关键统计视图并计算 diff,返回连接数、事务吞吐、缓存命中率、复制延迟等关键指标。 | 启用 |
| `postgres.activity` | 查询 `pg_stat_activity` 返回当前活跃和长时间运行的查询。 | 启用 |
| `postgres.query` | 执行受控只读 SQL 查询(SELECT/WITH/EXPLAIN 等)。 | 默认禁用 |
```yaml theme={null}
locator_mappings:
"localhost:5432": "pg-prod-01.example.com:5432"
postgres:
- targets:
- "localhost:5432"
connection:
database: postgres
sslmode: prefer
timeout: 3s
max_open_conns: 8
max_idle_conns: 2
overview:
sample_interval: 2s
activity:
min_query_age: 1s
top_n: 10
query:
enabled: false
default_max_rows: 200
statement_timeout: 6s
credential:
source: env_file
path: /etc/monit-agent/postgres.env
username_key: POSTGRES_USER
password_key: POSTGRES_PASSWORD
```
```text theme={null}
POSTGRES_USER=monit_ro
POSTGRES_PASSWORD=
```
| 配置 | 建议 |
| -------------------------- | ------------------------------------------------------------------------------- |
| `targets` | 显式写 `host:port`。默认端口 `5432`,如果使用 `localhost:5432`,建议配置 `locator_mappings`。 |
| `connection.database` | 必填。PostgreSQL 没有隐式默认数据库,常见值为 `postgres`。 |
| `connection.sslmode` | 默认 `prefer`。可选值:`disable`、`allow`、`prefer`、`require`、`verify-ca`、`verify-full`。 |
| `connection.timeout` | 建议 `3s`。 |
| `overview.sample_interval` | 建议 `2s` 或 `3s`,范围 `[1s, 5s]`。 |
| `activity.min_query_age` | 只返回运行时间超过此阈值的查询,默认 `1s`。 |
| `activity.top_n` | 默认 `5`,上限 `20`。 |
| `query.enabled` | 默认 `false`。只有确认账号是只读账号时再开启。 |
| `query.default_max_rows` | 建议 `200`,上限 `10000`。 |
| `query.statement_timeout` | 建议 `6s`,范围 `[1s, 7s]`。 |
| `credential` | 必填。PostgreSQL 线协议不支持匿名连接。建议授予 `pg_monitor` 角色以获得完整的 `pg_stat_activity` 可见性。 |
如果启用 `postgres.query`,请务必使用只读账号。
## MongoDB
如果需要诊断 MongoDB(mongod / 副本集成员),在 `mongodb:` 中添加实例配置。仅接受 `host:port` 格式,不支持 `mongodb+srv://` URI。
| 工具 | 功能 | 默认状态 |
| --------------------- | --------------------------------------------------- | ---- |
| `mongodb.overview` | 采集两次 serverStatus 并计算 diff,返回连接数、操作吞吐、内存、复制延迟等关键指标。 | 启用 |
| `mongodb.current_ops` | 查询 currentOp 返回当前运行中的操作。 | 启用 |
| `mongodb.command` | 执行受控只读管理命令(白名单策略)。 | 默认禁用 |
```yaml theme={null}
mongodb:
- targets:
- "10.1.3.10:27017"
- "10.1.3.11:27017"
connection:
database: admin
timeout: 3s
# tls:
# enabled: true
# ca_file: /etc/ssl/mongo-ca.pem
# allow_invalid_hostnames: false
overview:
sample_interval: 3s
command:
enabled: false
credential:
source: env_file
path: /etc/monit-agent/mongodb.env
username_key: MONGODB_USER
password_key: MONGODB_PASSWORD
```
```text theme={null}
MONGODB_USER=monit_ro
MONGODB_PASSWORD=
```
| 配置 | 建议 |
| -------------------------- | -------------------------------------------------------- |
| `targets` | 显式写 `host:port`。每条 target 对应一个独立的 mongod 实例。 |
| `connection.database` | SCRAM 认证的 authSource 库,默认 `admin`。 |
| `connection.timeout` | 建议 `3s`。 |
| `connection.tls` | 可选。开启 TLS 时设置 `enabled: true`,如使用自签 CA 指定 `ca_file`。 |
| `overview.sample_interval` | 建议 `3s`,范围 `[1s, 5s]`。 |
| `command.enabled` | 默认 `false`。只有确认需要执行受控只读管理命令时再开启。 |
| `credential` | 如果 MongoDB 未启用认证(开发/测试环境),可以不配置 credential。生产环境建议配置只读账号。 |
`mongodb.command` 启用后,只允许执行白名单内的只读管理命令,如 `dbStats`、`collStats`、`serverStatus`、`replSetGetStatus` 等。写命令和危险命令会被拒绝。
## MongoDB Mongos
如果需要诊断 MongoDB 分片集群的路由进程(mongos),在 `mongodb_mongos:` 中添加配置。`mongodb_mongos` 与 `mongodb` 是两种不同的对象类型,分别指向 mongos 路由进程和 mongod 数据节点。
| 工具 | 功能 | 默认状态 |
| ----------------------------------- | ----------------------------------------- | ---- |
| `mongodb_mongos.overview` | 采集 mongos 的 serverStatus,返回连接数、操作吞吐等关键指标。 | 启用 |
| `mongodb_mongos.shard_distribution` | 获取分片集群的拓扑和数据分布信息。 | 启用 |
```yaml theme={null}
mongodb_mongos:
- targets:
- "10.1.3.20:27017"
- "10.1.3.21:27017"
connection:
database: admin
timeout: 3s
overview:
sample_interval: 3s
credential:
source: env_file
path: /etc/monit-agent/mongodb.env
username_key: MONGODB_USER
password_key: MONGODB_PASSWORD
```
| 配置 | 建议 |
| -------------------------- | ---------------------------------- |
| `targets` | mongos 路由进程地址,显式写 `host:port`。 |
| `connection.database` | SCRAM 认证的 authSource 库,默认 `admin`。 |
| `connection.timeout` | 建议 `3s`。 |
| `overview.sample_interval` | 建议 `3s`,范围 `[1s, 5s]`。 |
| `credential` | 通常与 `mongodb` 共用凭据文件。 |
## Kafka
如果需要诊断 Kafka 集群,在 `kafka:` 中添加配置。Kafka 是集群级对象,一个 `kafka` 配置块代表一个逻辑集群,`bootstrap_brokers` 是连接入口点而非独立的 target。
| 工具 | 功能 | 默认状态 |
| -------------------- | --------------------------------------- | ---- |
| `kafka.overview` | 获取集群 Broker 列表、Controller 信息和 Topic 概览。 | 启用 |
| `kafka.consumer_lag` | 获取消费者组的消费延迟情况。 | 启用 |
| `kafka.topic_detail` | 获取指定 Topic 的分区详情(副本分布、ISR、Leader 等)。 | 启用 |
| `kafka.group_detail` | 获取指定消费者组的详情(成员分配、偏移量等)。 | 启用 |
```yaml theme={null}
kafka:
- cluster_name: "prod-order-kafka"
bootstrap_brokers:
- "10.1.4.10:9092"
- "10.1.4.11:9092"
- "10.1.4.12:9092"
connection:
timeout: 5s
sasl_mechanism: none
# tls:
# enabled: true
# ca_file: /etc/ssl/kafka-ca.pem
# cert_file: /etc/ssl/kafka-client.pem
# key_file: /etc/ssl/kafka-client-key.pem
consumer_lag:
default_top_n: 10
# credential:
# source: env_file
# path: /etc/monit-agent/kafka.env
# username_key: KAFKA_USER
# password_key: KAFKA_PASSWORD
```
| 配置 | 建议 |
| ---------------------------- | ------------------------------------------------------------------ |
| `cluster_name` | 必填。作为页面上的对象标识,只允许小写字母、数字、`.`、`-`、`_`,长度 2-128。 |
| `bootstrap_brokers` | 至少一个 Broker 地址,格式 `host:port`。建议填写多个以提高可用性。 |
| `connection.timeout` | 建议 `5s`。 |
| `connection.sasl_mechanism` | 默认 `none`。支持 `none`、`plain`、`scram-sha-256`、`scram-sha-512`。 |
| `connection.tls` | 可选。启用 TLS 时设置 `enabled: true`,mTLS 需同时配置 `cert_file` 和 `key_file`。 |
| `consumer_lag.default_top_n` | 默认 `10`,范围 `[1, 50]`。 |
| `credential` | 仅当 `sasl_mechanism` 不为 `none` 时需要配置。 |
Kafka 不使用 `locator_mappings`,`cluster_name` 直接作为页面上的对象地址。
## Elasticsearch
如果需要诊断 Elasticsearch 集群,在 `elasticsearch:` 中添加配置。Elasticsearch 是集群级对象,`cluster_name` 不需要在配置中声明,Agent 会在启动或 reload 时自动通过 `GET _cluster/health` 获取。如果集群不可达,该 target 会被跳过,直到下次 reload。
| 工具 | 功能 | 默认状态 |
| -------------------------------- | ---------------------------------- | ---- |
| `elasticsearch.overview` | 获取集群健康状态、节点数量、索引数量、分片分配等集群全局信息。 | 启用 |
| `elasticsearch.node_stats` | 获取各节点的 JVM、OS、线程池、transport 等详细指标。 | 启用 |
| `elasticsearch.index_stats` | 获取索引级别的文档数、存储大小、读写吞吐等统计信息。 | 启用 |
| `elasticsearch.shard_allocation` | 获取集群分片分配详情,诊断分片不均衡或未分配分片。 | 启用 |
| `elasticsearch.cat` | 执行受控的 `_cat` API 查询(白名单策略)。 | 默认禁用 |
```yaml theme={null}
elasticsearch:
- targets:
- "https://es-node1.example.com:9200"
- "https://es-node2.example.com:9200"
- "https://es-node3.example.com:9200"
connection:
timeout: 5s
tls:
ca_cert: /etc/ssl/es-ca.pem
skip_verify: false
cat:
enabled: false
credential:
source: env_file
path: /etc/monit-agent/elasticsearch.env
username_key: ES_USER
password_key: ES_PASSWORD
```
```text theme={null}
ES_USER=monit_ro
ES_PASSWORD=
```
| 配置 | 建议 |
| ---------------------------- | -------------------------------------------------------------------------------------- |
| `targets` | 完整 URL 格式,必须包含协议和端口,如 `https://es-node:9200`。支持 `http://` 和 `https://`。建议填写多个节点以提高可用性。 |
| `connection.timeout` | 建议 `5s`。 |
| `connection.tls.ca_cert` | 使用自签 CA 时指定 CA 证书路径,必须是绝对路径。 |
| `connection.tls.skip_verify` | 默认 `false`。不建议在生产环境开启。 |
| `cat.enabled` | 默认 `false`。开启后允许执行白名单内的 `_cat` API 查询。 |
| `credential` | 如果 Elasticsearch 未启用安全认证,可以不配置。生产环境建议配置只读账号。 |
Elasticsearch 不使用 `locator_mappings`,`cluster_name` 自动从集群获取作为页面上的对象地址。
# 安装 monit-agent
Source: https://docs.flashduty.com/zh/monitors/targets/install-agent
下载、启动并以系统服务方式运行 monit-agent,接入第一台主机监控对象
本文说明如何准备接入信息、安装 `monit-agent`,并将 Agent 启动为系统服务。
## 接入前准备
开始安装前,请准备以下信息:
| 准备项 | 说明 |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Agent 安装包下载地址 | `https://static.flashcat.cloud/monitagent/monitagent-v0.1.6-linux-amd64.tar.gz`。如果是 arm 的 CPU,则把 `amd64` 换成 `arm64`。 |
| Edge 地址 | 例如 `ws://edge.example.com:6868` 或 `wss://edge.example.com:6868`。Edge 版本需要 `>= v0.47.0`,Edge 列表和安装方法[点此查看](https://console.flashcat.cloud/monit/engine/list)。 |
| 本机对象地址 | 建议使用当前主机的固定内网 IP 或 DNS 名称,例如 `10.0.1.12`。不指定的话默认会使用本机默认路由对应的 IP。 |
| 数据库/中间件只读账号 | 如需诊断 MySQL、Redis、PostgreSQL、MongoDB、Kafka、Elasticsearch 等服务,需提前准备对应的只读账号和凭据。 |
Edge 地址必须带协议前缀,支持 `ws://`、`wss://`、`http://`、`https://`。生产环境建议使用 `wss://`,内网亦可使用 `ws://` 和 `http://`。
## 安装 monit-agent
以下步骤以 Linux 为例。
```bash theme={null}
sudo mkdir -p /opt/monit-agent
cd /opt/monit-agent
sudo curl -sfLO "https://static.flashcat.cloud/monitagent/monitagent-v0.1.6-linux-amd64.tar.gz"
sudo tar -xzf monitagent-v0.1.6-linux-amd64.tar.gz --strip-components=1
sudo chmod +x ./monitagent
```
解压后目录中应包含:
```text theme={null}
/opt/monit-agent/monitagent
/opt/monit-agent/agent.yaml
```
确认二进制可执行:
```bash theme={null}
/opt/monit-agent/monitagent --version
```
## 前台启动
最小启动命令如下:
```bash theme={null}
sudo /opt/monit-agent/monitagent \
--agent.edgeAddresses="ws://:" \
--agent.configFile="/opt/monit-agent/agent.yaml" \
--agent.hostLocator=""
```
| 参数 | 是否必填 | 说明 |
| ----------------------- | ---- | ------------------- |
| `--agent.edgeAddresses` | 是 | Agent 要连接的 Edge 地址。 |
| `--agent.configFile` | 建议填写 | Agent 配置文件路径。 |
| `--agent.hostLocator` | 否 | 页面上显示的当前主机对象地址。 |
如果不填写 `--agent.hostLocator`,Agent 会自动选择本机默认出口 IP 作为主机对象地址。建议和你的监控系统中的机器标识保持一致。
## 配置多个 Edge 地址
如果有多个 Edge 地址,用英文逗号分隔:
```bash theme={null}
sudo /opt/monit-agent/monitagent \
--agent.edgeAddresses="ws://edge-a.example.com:6872,ws://edge-b.example.com:6872" \
--agent.configFile="/opt/monit-agent/agent.yaml" \
--agent.hostLocator="10.0.1.12"
```
Agent 会自动重连。当前连接不可用时,会继续尝试其它 Edge 地址。
## 使用 Basic Auth 或 TLS
如果 Edge 开启了 Basic Auth,需要同时传入用户名和密码:
```bash theme={null}
sudo /opt/monit-agent/monitagent \
--agent.edgeAddresses="wss://edge.example.com:6872" \
--agent.edgeBasicUser="" \
--agent.edgeBasicPass="" \
--agent.configFile="/opt/monit-agent/agent.yaml" \
--agent.hostLocator="10.0.1.12"
```
如果 Edge 使用私有 CA 证书,可以指定 CA 文件:
```bash theme={null}
sudo /opt/monit-agent/monitagent \
--agent.edgeAddresses="wss://edge.example.com:6872" \
--agent.edgeTLSCAFile="/etc/monit-agent/edge-ca.pem" \
--agent.configFile="/opt/monit-agent/agent.yaml" \
--agent.hostLocator="10.0.1.12"
```
配置 TLS 参数时,Edge 地址应使用 `wss://` 或 `https://`。
## 安装为系统服务
确认前台启动正常后,建议安装为系统服务:
```bash theme={null}
cd /opt/monit-agent
sudo ./monitagent \
--agent.edgeAddresses="ws://:" \
--agent.configFile="/opt/monit-agent/agent.yaml" \
--agent.hostLocator="" \
--audit.dir="/var/log/monit-agent/audit" \
--install
sudo ./monitagent --start
sudo ./monitagent --status
```
查看日志:
```bash theme={null}
sudo journalctl -u monitagent -f
```
如果修改了 Edge 地址、Basic Auth、TLS 参数或 `hostLocator`,需要重启 Agent。修改 `agent.yaml` 后,可以发送 SIGHUP 让 Agent 重新加载配置:
```bash theme={null}
sudo systemctl kill -s HUP monitagent
```
## 人工审批被拦截的 Shell 命令
`shell.exec` 会自动执行符合内置安全规则的只读诊断命令。如果某条命令未通过自动规则,但你确认它可以在当前机器上执行,可以提前登录 Agent 所在的 Linux 主机,用 root 打开审批会话:
```bash theme={null}
sudo /opt/monit-agent/monitagent shell-approval
```
审批会话连接成功后会显示等待提示。出现待审批命令时,终端只展示命令本身和 10 秒倒计时:
* 按回车批准当前批次中的全部命令。
* 按 `n` 拒绝当前批次中的全部命令。
* 10 秒内没有操作时自动拒绝;并发到达的后续命令会排队,并在显示后获得完整的 10 秒审批时间。
* 没有待审批命令时,输入不会触发执行,终端会继续显示等待状态。
* 按 `Ctrl-C` 退出审批会话。
同一台 Agent 同时只允许一个审批会话。如果已有会话且你需要接管,使用:
```bash theme={null}
sudo /opt/monit-agent/monitagent shell-approval --replace
```
只有 root 可以打开或接管会话。Agent 重启或会话断开时,待审批命令会被拒绝;重启后需要重新打开会话。关机、重启、破坏系统或读取敏感凭据等高危操作不能通过人工审批放开。
## 下一步
Agent 启动成功后,通常几秒内可以在监控对象页面看到一个主机对象。接下来可以继续阅读[配置监控对象](/zh/monitors/targets/configure-targets),在 `agent.yaml` 中添加数据库和中间件对象。
# 监控对象概览
Source: https://docs.flashduty.com/zh/monitors/targets/overview
了解 Monitors 监控对象的含义、monit-agent 的作用,以及对象如何自动出现在页面上
监控对象是 Monitors 可以查询和诊断的目标。安装并启动 `monit-agent` 后,平台会自动展示 Agent 能诊断的主机、数据库和中间件对象。
## 为什么需要 monit-agent
传统可观测性数据通常包括指标、日志、链路追踪和告警事件。这些数据能帮助你判断“发生了什么”,但在实际排障时,经常还需要进一步确认现场状态,例如:
* 当前机器上哪些进程占用 CPU 或内存较高。
* 某个端口、域名或服务是否能从目标机器访问。
* 磁盘、挂载点、网卡、连接数等运行状态是否异常。
* MySQL 当前变量、连接状态、关键指标或只读 SQL 查询结果。
* Redis 内存、命中率、慢查询或任意只读命令执行结果。
* PostgreSQL 连接活动、锁等待、慢查询或只读 SQL 查询结果。
* MongoDB 副本集状态、当前操作、只读管理命令执行结果。
* Kafka 集群 Broker 状态、消费者延迟、Topic 和 Group 详情。
* Elasticsearch 集群健康、节点指标、索引统计和分片分配。
这些问题只靠已经采集上来的数据不一定能回答,很多时候需要“连到现场查一下”。`monit-agent` 就是为这个场景设计的。
在 AI-SRE 场景下,可以把 LLM 理解为诊断大脑,把 `monit-agent` 理解为部署在用户环境里的现场执行端。用户用自然语言提出问题后,LLM 负责理解问题、选择合适的诊断工具并解释结果;`monit-agent` 负责在目标主机或目标服务附近执行受控查询,并把结构化结果返回给系统。
`monit-agent` 的重点不是让 LLM 获得无限制的执行权限,而是提供一个安全、受控、可审计的执行边界。Agent 内置工具白名单、参数校验、命令限制、超时控制、输出截断、敏感信息脱敏、本地禁用开关和审计记录。
## 技术架构

`monit-agent` 通过 WebSocket 连接到同网络区域内的 `monitedge`。`monitedge` 再通过 WebSocket 连接到 SaaS 中心。通常每个网络区域部署一套 `monitedge`,同一个 `EngineName` 的多个 `monitedge` 实例会被视为同一套引擎集群。
## 支持的对象类型
| 对象类型 | 含义 | 页面上的地址示例 |
| -------------- | ---------------------------------------- | -------------------------------------- |
| 主机 | 安装并运行 `monit-agent` 的服务器 | `10.0.1.12`、`host-prod-01.example.com` |
| MySQL | 在 `agent.yaml` 中配置的 MySQL 实例 | `db-prod-01.example.com:3306` |
| Redis | 在 `agent.yaml` 中配置的 Redis 实例 | `redis-prod-01.example.com:6379` |
| Redis Sentinel | 在 `agent.yaml` 中配置的 Redis Sentinel 进程 | `10.1.2.10:26379` |
| PostgreSQL | 在 `agent.yaml` 中配置的 PostgreSQL 实例 | `pg-prod-01.example.com:5432` |
| MongoDB | 在 `agent.yaml` 中配置的 MongoDB 实例(mongod) | `10.1.3.10:27017` |
| MongoDB Mongos | 在 `agent.yaml` 中配置的 MongoDB 路由进程(mongos) | `10.1.3.20:27017` |
| Kafka | 在 `agent.yaml` 中配置的 Kafka 集群 | `prod-order-kafka`(`cluster_name`) |
| Elasticsearch | 在 `agent.yaml` 中配置的 Elasticsearch 集群 | 自动从集群获取 `cluster_name` |
安装并启动 `monit-agent` 后,页面上至少会出现一个主机对象。其他对象类型需要在 `agent.yaml` 中配置后才会出现。
对象标识(`target_locator`)建议使用稳定、容易识别的值,例如固定内网 IP 或 DNS 名称。不要使用 `localhost`、`127.0.0.1` 这类只在本机有意义的地址作为页面展示地址。
## 对象如何出现在页面上
监控对象不需要在页面上手工创建。你只需要在目标机器上安装并启动 `monit-agent`。Agent 成功连接到 Edge 后,会自动把自己能诊断的对象上报到平台,页面就会展示这些对象。
因此,新用户首次进入监控对象页面时列表为空,通常表示还没有任何 Agent 成功接入。接入第一台 Agent 后,页面一般会先出现一个主机对象;如果后续在配置文件中增加 MySQL、Redis、PostgreSQL 等服务,对应的对象也会自动出现。
## 建议接入路径
先接入主机对象,确认 Agent 可以连接 Edge,并能在页面展示当前主机。
在 `agent.yaml` 中逐步添加 MySQL、Redis、PostgreSQL、MongoDB、Kafka、Elasticsearch 等对象。
对象出现后,再按需开启 `mysql.query`、`redis.command`、`postgres.query`、`mongodb.command`、`elasticsearch.cat` 等受控查询工具。
## 相关文档
准备 Edge 地址,下载 Agent,并配置前台启动或系统服务。
配置主机、数据库、中间件和受控诊断工具。
# 配置生效与接入验证
Source: https://docs.flashduty.com/zh/monitors/targets/reload-and-verify
了解 monit-agent 配置变更的生效方式,并排查监控对象没有出现在页面上的常见问题
修改 `monit-agent` 配置后,不同类型的变更需要不同的生效方式。本文说明何时 reload、何时重启,以及如何确认监控对象已经成功接入。
## 配置生效规则
| 变更内容 | 生效方式 |
| ------------------------------------------------------------------------------- | ---------------- |
| `agent.yaml` 中的主机采集、工具开关、MySQL、Redis、PostgreSQL、MongoDB、Kafka、Elasticsearch 等配置 | 发送 SIGHUP reload |
| Edge 地址、Basic Auth、TLS、`hostLocator`、审计目录 | 重启 Agent |
发送 SIGHUP:
```bash theme={null}
sudo systemctl kill -s HUP monitagent
```
重启服务:
```bash theme={null}
sudo systemctl restart monitagent
```
如果只是新增或调整 `agent.yaml` 中的对象配置,优先使用 SIGHUP reload。只有启动参数或服务级参数变化时才需要重启。
修改工具开关后,成功 reload 即可更新 Agent 当前可用的诊断工具,无需重启。
## 验证接入是否成功
启动 Agent 后,通常几秒内可以在监控对象页面看到一个主机对象。
如果页面仍为空,请按以下顺序检查:
```bash theme={null}
sudo systemctl status monitagent
```
检查地址是否带了 `ws://` 或 `wss://`,并确认当前租户对应的 Edge 已经在线。
```bash theme={null}
sudo journalctl -u monitagent -n 100
```
如果修改过 `agent.yaml`,确认配置文件没有 YAML 语法错误。
## 对象没有出现时的检查项
| 现象 | 检查方向 |
| ----------------------------------- | ----------------------------------------------------------------------- |
| 监控对象页面为空 | 先确认主机对象是否出现;如果主机对象都没有出现,优先检查 Agent 进程、Edge 地址和日志。 |
| 某类数据库或中间件对象没有出现 | 检查对应的 `targets`、`locator_mappings` 和凭据文件配置。 |
| Elasticsearch 对象没有出现 | 确认集群可达。Agent 需要在启动或 reload 时通过 `GET _cluster/health` 获取 `cluster_name`。 |
| 页面对象地址显示为 `localhost` 或 `127.0.0.1` | 为该 target 配置 `locator_mappings`,映射为固定内网 IP、DNS 或 `host:port`。 |
## 推荐接入顺序
1. 先只接入主机对象。
2. 页面出现主机后,再逐步添加 MySQL、Redis、PostgreSQL 等数据库对象。
3. 各对象出现后,再按需开启 `mysql.query`、`redis.command`、`postgres.query`、`mongodb.command`、`elasticsearch.cat` 等受控查询工具。
## 相关文档
了解监控对象和 monit-agent 的工作方式。
查看 agent.yaml 中各对象类型的配置示例和建议。
# ServiceMap(服务地图)
Source: https://docs.flashduty.com/zh/monitors/targets/servicemap
基于 eBPF 实时连接证据自动生成的服务依赖拓扑,帮你确认某台主机或服务当前真实在和谁通信
**Beta 功能**:ServiceMap 处于 Beta 阶段,功能与界面可能继续调整。它依赖 `monit-agent` 的 eBPF 观测能力——Agent 版本过低、运行环境不支持或未启用 ServiceMap 时,主机会显示为「不支持」或「未启用」,没有拓扑数据。
ServiceMap 根据 `monit-agent` 通过 eBPF 观测到的真实网络连接,自动构建主机、进程、容器和工作负载之间的依赖拓扑。它不依赖任何手工配置或静态架构图,展示的是"此刻这台机器实际在和谁通信",而不是"文档里写的应该和谁通信"。
**入口**:监控对象页面(对象列表里每一行的"拓扑"按钮,或工具栏的"ServiceMap 主机"按钮)。
## 概述
拓扑里的每一条依赖(边)来自 Agent 观测到的一次真实连接:源实体(进程、容器或工作负载)向某个目标端点(`ip:port/protocol`)发起了 `connect`。ServiceMap 的解析器会尝试把这个目标端点匹配到同一网络作用域内的某个已知监听者,从而把一条"连接"变成一条"服务依赖":
* 如果端点唯一匹配到一个监听者,这条依赖标记为**已确认**。
* 如果端点匹配到多个可能的监听者,标记为**候选**,需要你结合上下文判断真正的对端。
* 如果端点没有匹配到任何监听者,标记为**未解析**,默认不进入拓扑画布(避免外部地址、短暂连接等噪音掩盖真实依赖)。
在故障排查时,ServiceMap 用来快速确认"这台主机 / 这个服务当前的直接依赖和被依赖方是谁",判断变更或异常的影响半径,而不需要临时登录主机逐个排查连接。在监控对象列表中点击"AI分析"时,如果该主机的 ServiceMap 拓扑可用且你有权限查看,系统会自动把当前拓扑摘要作为上下文一并提供给 AI-SRE,不需要手动附加。
查看 ServiceMap 需要 `MonitServiceMapVisit` 权限。没有该权限时,拓扑抽屉会提示"需要 ServiceMap Read 权限才能查看当前拓扑",对象列表和主机列表本身仍可正常使用。
## 如何打开 ServiceMap
在监控对象页面(`/monit/targets`),有两个入口:
* **对象列表里的"拓扑"按钮**:当某一行满足以下全部条件时,操作列会出现"拓扑"链接,点击后直接打开该主机的当前拓扑。
* `host_id` 存在且格式合法;
* 该对象上报了 `servicemap` 能力且没有错误码;
* `graph_available` 为真(当前有可读取的图);
* ServiceMap 状态为**正常**、**降级**或**已过期**三者之一。
* **工具栏的"ServiceMap 主机"按钮**:打开全账号范围的 ServiceMap 主机列表(见下文"主机列表"),可以按 Agent 版本、Edge 集群、采集模式、状态筛选后再进入某一台主机的拓扑,同样受上面这条规则约束。
打开后的拓扑抽屉包含两个标签页:**拓扑**(可视化画布)和**数据详情**(查询信息 + 依赖明细表格),标题栏会显示当前图是"实时"还是"已过期"、采集模式,以及观测时间。
## 拓扑画布
### 解析状态筛选
画布上方是一组按钮,对应依赖的解析状态,每个按钮都带数量角标:
| 按钮 | 含义 |
| ----------- | ---------------------------------------------------------- |
| **已确认** | 已解析到唯一对端服务的依赖。点击可切换画布中已确认依赖节点/连线的显示与隐藏。 |
| **候选** | 存在多个可能对端、尚未唯一确定的依赖。点击同样可切换显示与隐藏。 |
| **未解析**(红色) | 点击不是切换画布可见性,而是打开"未解析端点分组"抽屉(见下文)。未解析端点默认不进入画布。数量为 0 时按钮禁用。 |
如果某条依赖的解析状态既不是"已确认"也不是"候选/未解析"(后端返回状态为已确认,但候选数量并不等于 1 的异常数据),工具栏会额外出现一个**未知 N** 的标签作为提示,这类连线在画布中以灰色点划线呈现。
### 跳数与聚焦模式
* 未进入聚焦模式时,工具栏左侧是"范围"选择器,可选 **1 跳 / 2 跳 / 3 跳**。这是一次新的后端查询(不是纯前端过滤):跳数越大,加载的节点和边越多,也更容易触发查询上限。单次查询默认最多返回 100 个节点、200 条边。
* **双击任意节点**进入聚焦模式:画布只保留以该节点为中心、按上下游方向展开的局部依赖图。进入聚焦时上游跳数固定重置为 1 跳,下游跳数保留你上次设置的值(初始为 1 跳);上游、下游跳数可以分别独立调整为 0~3 跳。上游边代表调用你的一方,下游边代表你依赖的一方。
* 也可以用画布右上角的搜索框(按名称、ID、容器或工作负载搜索)直接定位并聚焦某个节点。
* 点击"退出聚焦"或按 Esc 可退出聚焦,回到当前跳数范围内的整体拓扑。
### 画布控制与交互
* 左下角提供**放大 / 缩小**、当前缩放百分比,以及**显示/隐藏小地图**。
* **适应画布**把整张图缩放到可见范围;**重新布局**用新的随机种子重新排列节点位置(用于拆开重叠严重的节点)。
* 悬停在某个节点上时,与它直接相连的节点/连线保持高亮,其余整体变淡;从该节点**发出**的连线(它的下游依赖)会额外显示指标标签,例如 `↑ 12.3 KB/s` / `↓ 4.1 KB/s`(发送/接收速率)、`✕ 3`(观测窗口内的连接失败次数)、`↻ 2`(重传次数),或在没有明显速率数据时显示 `● 5`(当前活跃连接数)。速率只在该窗口指标完整时才展示。
* 单击节点或连线会在右侧打开详情面板(见下文),面板宽度可拖拽调整;单击画布空白处清除选中。
* 画布左上角常驻一组统计卡片:**服务**(节点数)、**已确认依赖**、**已检查依赖**(本次查询实际检查过的依赖总数,含已确认/候选/未解析)。
* 当本次查询触发截断(达到节点/边上限)时,画布上方会出现"已检查 N 条依赖,达到查询上限"的提示条,附带"聚焦服务"按钮,方便你直接搜索并聚焦到关心的服务,缩小范围重新查看。
节点形状和连线颜色是判断依赖可信度的第一层信号:
| 视觉表现 | 含义 |
| ----------- | ------------------------------------------------ |
| 圆形节点 | 已知实体(进程 / 容器 / 工作负载) |
| 圆形节点 + 问号图标 | 候选节点:某条"候选"依赖的一个可能对端实体 |
| 菱形节点 | 尚未归并为实体的目标端点:候选依赖展开出的端点节点,或通过"未解析端点"面板临时定位的未解析端点 |
| 绿色实线 | 已确认依赖 |
| 橙色虚线(带动画) | 候选依赖,会从端点菱形节点分别连向多个候选实体 |
| 红色点划线 | 未解析依赖,仅在你主动"定位来源"时临时出现 |
| 灰色点划线 | 未知(后端标记为已确认但候选数量异常的数据) |
## 节点详情
单击一个实体或候选节点,右侧详情面板会按三组展示信息:
| 分组 | 字段 | 说明 |
| --- | ------------ | ---------------------------------------------------- |
| 身份 | 显示名称 | 该实体在页面上展示的名称 |
| | 类型 | 实体类型(如 `process_workload`、`container`) |
| | Entity ID | 实体的唯一标识 |
| | Host ID | 实体所在主机的标识 |
| 运行时 | 可执行文件 | 该实体对应的可执行文件名 |
| | Systemd Unit | 该实体对应的 systemd 服务单元(如有) |
| | 容器 | 容器名称(如实体运行在容器内) |
| | 镜像 | 镜像仓库和版本,格式为 `repository:version` |
| | 工作负载 | Kubernetes 命名空间/工作负载名称,格式为 `namespace/workload_name` |
| | 实例数 | 归并到该实体下的实例数量 |
| 观测 | 首次观测 | 该实体首次被观测到的时间 |
| | 最近观测 | 该实体最近一次被观测到的时间 |
| | 实体身份 | 后端返回的原始身份标识(JSON),用于精确排查 |
每一行右侧悬停会出现复制按钮,可以直接复制该字段的原始值。面板顶部还有一个"只看它的上下游"按钮,可以从详情面板直接对该节点发起聚焦。
## 依赖详情
单击一条连线(或一个候选/端点节点),详情面板会展示这条依赖的三组信息:
| 分组 | 字段 | 说明 |
| -- | ----------- | ------------------------------------------------------- |
| 标识 | Edge ID | 该依赖的唯一标识 |
| | 源 Entity ID | 发起连接的源实体 ID |
| | 源 NetNS ID | 源实体所在的网络命名空间 ID |
| | 目标端点 | 目标端点,格式为 `ip:port/protocol` |
| | 证据 | 该依赖被观测到的方式(自由文本,例如 `connect`,表示通过一次 connect 系统调用观测到该连接) |
| 解析 | 解析状态 | `resolved` / `ambiguous` / `unresolved` 等原始解析状态 |
| | 解析原因 | 解析器返回的原因说明 |
| | 候选数量 | 解析器为该端点找到的可能对端服务数量,大于 1 时依赖标记为候选 |
| | 候选被截断 | 候选列表超过返回上限时为"是",此时只返回了部分候选 |
| | 匹配类型 | 候选的匹配方式(如 `exact` 精确匹配、`wildcard` 通配匹配) |
| | 置信度 | 该候选的置信度数值 |
| | Listener ID | 候选对端实际监听器的标识 |
| 观测 | 首次观测 | 该依赖首次被观测到的时间 |
| | 最近观测 | 该依赖最近一次被观测到的时间 |
判断一条依赖是否可信,优先看**解析状态**和**候选数量**:候选数量为 1 才会被判定为已确认;候选数量大于 1 时属于候选依赖,需要结合**匹配类型**和**置信度**判断哪个候选更可能是真实对端。
## 数据详情标签页
拓扑抽屉的"数据详情"标签页提供一个不依赖画布交互的表格视图,标签本身会显示已确认依赖的数量角标,包含两部分:
**查询信息**:展示本次查询的 Host ID、Network Scope、观测时间、方向与深度、覆盖主机数等(字段含义详见下一节"如何判断拓扑是否可信")。
**依赖明细**:仅列出已确认和候选依赖(不含未解析),每行包含来源、目标、协议端口、置信度(高 / 中 / 低)、最近观测时间。置信度按该依赖候选中的最高置信度值分级:不低于 0.85 为高,不低于 0.5 为中,其余为低。
## 未解析端点
未解析端点指目标端点没有匹配到任何已知监听者的依赖。它们默认不进入拓扑画布,而是通过独立的"未解析端点分组"抽屉按原因分组展示。
打开方式:点击画布顶部的"未解析"筛选按钮。首次打开时,如果当前拓扑查询使用的是摘要模式(只有分组计数、没有具体端点列表),会自动发起一次补充查询加载完整列表。
已知的分组原因及说明:
| 原因 | 说明 |
| --------------------------------- | -------- |
| `no_current_listener` | 未发现当前监听器 |
| `listener_address_family_unknown` | 监听地址族不确定 |
| `invalid_endpoint` | 端点信息无效 |
后端返回其他未预置文案的原因时,会用通用的"未解析"标签展示,原始原因字符串仍会一并显示。
在某个分组内,你可以:
* 用左上角的搜索框按目标端点或来源服务过滤当前分组内的记录;
* 点击某一行的"定位来源"图标,关闭抽屉并在画布上临时高亮这条未解析依赖的来源实体和目标端点(对应画布上的"正在定位未解析端点"提示条,点击"退出定位"或按 Esc 退出);
* 点击右上角"导出 CSV",导出全部未解析端点(不限于当前选中分组),CSV 列依次为:**目标端点**、**来源服务**、**源 Entity ID**、**解析原因**。
## 主机列表
从工具栏的"ServiceMap 主机"按钮打开,展示账号下所有上报了 ServiceMap 能力的主机,独立于单台主机的拓扑视图。
**筛选条件**:Agent 版本(多值输入,回车确认,最多 20 个)、Edge 集群(多值输入,回车确认,最多 20 个)、采集模式(多选:eBPF / Polling / 未知)。
**状态分布**:一组统计卡片,按固定顺序展示"正常 / 降级 / 已过期 / 初始化中 / 未启用 / 不支持 / 暂无数据"七种状态各自的主机数,点击某个卡片即可按该状态筛选下方列表(再点击一次或点"清除状态筛选"取消)。卡片上方展示扫描覆盖信息:"扫描 N 台(上限 M),匹配 X 台,成功分类 Y 台,失败 Z 台",以及计数生成时间。如果本次统计是有界扫描(达到扫描上限)或部分主机状态读取失败,会分别提示"仅代表本次有界扫描"或"计数不完整"。
各状态的含义:
| 状态 | 含义 |
| ---- | -------------------------------- |
| 正常 | 当前拓扑新鲜且可用于分析 |
| 降级 | 采集仍在运行,但当前证据不完整或不是 authoritative |
| 已过期 | 最后可信拓扑已超过新鲜度窗口 |
| 初始化中 | Agent 正在生成首个可用快照 |
| 未启用 | 该 Agent 未启用 ServiceMap |
| 不支持 | 当前 Agent 或运行环境不支持 ServiceMap |
| 暂无数据 | 已发现能力,但还没有可用的当前拓扑 |
监控对象列表和主机列表还可能出现两种额外的展示态:**未上报**(Agent 未上报 ServiceMap 能力,不能直接判断为不支持)和**状态不可用**(ServiceMap 状态暂时无法读取,监控对象本身仍可用)。这两种不是 ServiceMap 状态的正式取值,只是状态列自身的容错展示。
**主机列表**:列出 Host ID、Agent 版本、Edge 集群(即接入该主机 Agent 的 monitedge 集群名)、ServiceMap 状态、采集模式、拓扑观测时间;满足前文"如何打开 ServiceMap"条件的行会出现"拓扑"操作按钮,点击直接打开该主机的拓扑。
列表采用游标分页、按需加载,因此在加载完所有匹配结果之前无法知道精确总数:底部会显示"已加载 N 台主机"(还有更多可加载)或"共 N 台主机"(已经是全部结果)。如果本次浏览达到扫描边界或部分主机状态不可用,列表上方会提示"主机列表达到扫描边界或部分状态不可用,请继续翻页或收窄筛选"。
## 如何判断拓扑是否可信
拓扑是根据近期观测窗口内的连接证据生成的,不是实时快照,也不保证完整。打开任意一台主机的拓扑后,可以从"数据详情"标签页的"查询信息"区块(以及拓扑抽屉标题栏、画布顶部提示条)综合判断这份拓扑有多可信:
| 字段 | 说明 |
| --------------------- | ------------------------------------------------------------------------------------------------ |
| Network Scope | 网络作用域标识,端点解析只在同一作用域内进行。默认按 Edge 集群自动划分作用域,无需手动配置。 |
| 采集模式 | 产生这份拓扑证据的采集方式,例如 `ebpf` 内核观测;也可能是 `polling` 或 `hybrid`。 |
| 新鲜度 | `fresh` 表示证据在观测窗口内、可视为实时;其他状态说明这份图已经过期,抽屉标题栏会显示"已过期"标签,并额外提示"请结合观测时间和 coverage 判断,不要将过期图当作实时依赖"。 |
| 覆盖主机 | 本次拓扑查询实际加载的主机数量。 |
| Network Inventory | 监听端点清单投影的状态,影响端点解析的完整性(例如该投影是否完整可用)。 |
| Kubernetes Enrichment | Kubernetes 元数据富化状态,影响容器与工作负载信息是否完整。 |
| 查询限制 | 本次查询触发的截断原因列表,**出现即说明这份图不完整**(例如达到节点或边数上限)。 |
当拓扑存在降级或不完整证据时(`degraded_hosts` 大于 0,或存在降级原因),抽屉会额外提示"当前拓扑包含降级或不完整证据";查询本身超时或被限流时,会分别提示"请稍后重试或降低深度"和"请稍后重试"。这些都不是错误,而是提醒你此时看到的依赖关系可能不完整,建议缩小跳数范围或稍后重试。
简单来说:**新鲜度不是 `fresh`**、**查询限制列表不为空**、或**降级/不完整证据提示出现**,都说明当前这份拓扑不能当作实时、完整的依赖关系直接下结论,需要结合观测时间进一步确认。
# RUM 告警太多?从这里开始配置
Source: https://docs.flashduty.com/zh/rum/best-practices/alert-noise-reduction
通过数据过滤、告警分级与 Flashduty 协同,让 RUM 告警聚焦关键问题,减少无效干扰。
Flashduty RUM 提供了从数据过滤、告警分级到 Flashduty 告警处理的完整链路。合理配置这一链路,可以有效降低告警噪音,让团队专注于真正重要的问题。
本文将介绍 RUM 告警配置的核心原则和典型场景方案,帮助您快速减少无效告警干扰。
本文涉及的过滤和分级配置均在控制台「应用管理」中完成:选择目标应用,点击左侧「告警设置」即可配置。详细配置说明请参考
[Issue 告警](/zh/rum/error-tracking/issue-alerts)。

## 告警处理链路
RUM 告警从 Error 产生到通知到人,经过以下四层处理:
| 层级 | 配置位置 | 核心作用 |
| ------ | ------------------- | -------------------------- |
| ① 数据过滤 | RUM 应用 → 告警设置 | 在源头排除不需要的 Error,减少无效 Issue |
| ② 告警分级 | RUM 应用 → 告警设置 | 根据 Error 属性设定 Issue 优先级 |
| ③ 告警处理 | Flashduty 集成 → 告警处理 | 基于 Issue 维度做优先级调整、丢弃/抑制 |
| ④ 告警分派 | Flashduty 协作空间 | 路由到团队、通知值班人员 |
配置时建议**从上到下依次设置**:先过滤噪音,再分级告警,最后在 Flashduty 侧做精细化处理。
## 第一步:过滤噪音数据
在配置告警分级之前,先清理数据源。常见的噪音来源包括:
浏览器扩展或第三方广告/分析脚本产生的错误与您的业务无关,建议排除:
* 错误堆栈 包含 `chrome-extension://`
* 错误堆栈 包含 `moz-extension://`
* 错误堆栈 包含 `cdn.third-party.com`
某些错误频繁出现但不影响用户体验:
* 错误消息 包含 `ResizeObserver loop`
* 错误消息 包含 `Script error`
如果您只关注生产环境的告警,可以过滤其他环境的错误:
* 环境 不包含 `production`
被过滤的 Error 不会参与 Issue
聚合和告警,但数据仍然保留,您可以在查看器中通过筛选条件查看这些被过滤的错误。
## 第二步:配置告警分级
过滤噪音后,通过告警分级规则区分不同错误的重要程度。
### 分级策略建议
| 优先级 | 适用场景 | 期望响应时间 |
| ---------------- | ----------------------- | ------ |
| **P0(Critical)** | 核心业务中断、VIP 用户受影响、生产环境崩溃 | 立即响应 |
| **P1(Warning)** | 重要功能异常、核心页面错误 | 当日处理 |
| **P2(Info)** | 非核心功能错误、低影响问题 | 按计划处理 |
### 推荐规则配置
以下是按业务优先级从高到低排列的推荐规则:
崩溃意味着应用完全不可用,需要最高优先级响应。
* 条件:环境 包含 `production`,且 是否崩溃 包含 `true`
* 告警级别:P0
VIP 用户的体验直接关系到商业价值。
* 条件:用户 ID 包含 `vip`(或通过自定义字段 `context.user.level` 包含 `vip` 来匹配)
* 告警级别:P0
支付、登录、结算等核心业务页面的错误需要优先处理。
* 条件:页面 URL 包含 `/payment`
* 告警级别:P1
可以为每个核心页面创建单独的规则,或在同一规则中使用多个匹配值。
未匹配任何规则的错误自动归为 P2,按常规流程处理。无需额外配置。
规则数量建议控制在 3-6
条,覆盖最关键的场景即可。过多的规则会增加维护成本,且容易导致优先级混乱。
## 第三步:在 Flashduty 中精细化处理
RUM 侧的告警分级基于单个 Error 的属性,如需基于 Issue 的整体影响做进一步处理,可以在 Flashduty 的[告警处理 Pipeline](/zh/on-call/integration/alert-integration/alert-pipelines) 中配置。
| 处理场景 | 配置方式 |
| ------- | ------------------------------------------------------------------------- |
| 抑制重复告警 | 同一 `alert_key` 在 1 小时内只告警一次 |
| 自定义告警标题 | 模板示例:`[RUM] [{{Labels.env}}] {{Labels.error_type}} - {{Labels.view_url}}` |
| 低影响错误降级 | 当 `labels.affected_users` \< 5 时,将严重程度更新为 Info |
## 典型场景方案
电商应用的核心是交易流程,告警配置应围绕支付和下单环节展开。
| 层级 | 配置 |
| ---- | ---------------------------------- |
| 数据过滤 | 排除:第三方广告脚本错误、`ResizeObserver loop` |
| 告警分级 | P0:支付页面错误、崩溃;P1:商品详情页/购物车错误 |
| 告警处理 | 抑制窗口:30 分钟;标题模板包含页面路径 |
| 告警分派 | P0 → 短信+电话通知,P1 → IM 通知 |
SaaS 应用需要关注不同租户的体验差异。
| 层级 | 配置 |
| ---- | --------------------------------------------------- |
| 数据过滤 | 排除:浏览器扩展错误、非生产环境 |
| 告警分级 | P0:企业版租户错误(通过 `context.tenant.plan` 匹配);P1:核心功能页面错误 |
| 告警处理 | 标题模板包含租户信息;低影响告警降级 |
| 告警分派 | 按团队分配到不同协作空间 |
内容型网站对可用性要求相对宽松,重点关注加载和渲染问题。
| 层级 | 配置 |
| ---- | --------------------------- |
| 数据过滤 | 排除:第三方脚本错误、`Script error` |
| 告警分级 | P0:崩溃;P1:首页/搜索页错误 |
| 告警处理 | 抑制窗口:1 小时;影响用户数 \< 10 的告警降级 |
| 告警分派 | P0 → IM 通知,P1/P2 → 邮件通知 |
## 常见问题
| 对比 | RUM 数据过滤 | Flashduty 告警丢弃 |
| ---- | -------------------------- | ------------------- |
| 作用时机 | Error 聚合为 Issue 之前 | Issue 投递为告警之后 |
| 数据留存 | Error 数据保留,可在查看器中查看 | Issue 数据保留 |
| 影响范围 | 被过滤的 Error 不参与 Issue 聚合和告警 | Issue 已存在,只是不产生告警通知 |
| 适用场景 | 长期排除的噪音数据 | 灵活的告警控制 |
两者互补,适用于不同维度的判断:
* **RUM 告警分级**:基于单个 Error 的属性(用户、页面、环境等),适合在源头快速判定
* **Flashduty Pipeline**:基于 Issue 的整体信息(影响用户数、错误数量等),适合做更全面的评估
建议在 RUM 侧设定基础优先级,在 Flashduty 侧做补充调整。
不会。如果不配置任何过滤规则和告警分级,所有 Error 仍然会聚合为 Issue 并以默认严重程度投递到 Flashduty。现有行为完全保持不变。
## 延伸阅读
告警触发条件、自定义分级和数据过滤的完整配置说明
在集成层对告警进行清洗、转换和过滤
在协作空间层面聚合和抑制告警
配置分派策略,将告警路由到正确的值班人员
# 分布式追踪功能
Source: https://docs.flashduty.com/zh/rum/best-practices/distributed-tracing
了解如何在 Flashduty RUM 中配置和使用分布式追踪功能,实现前后端请求链路的完整监控
## 概述
Flashduty RUM 的 **Trace 追踪**功能将前端用户监控与分布式追踪系统深度集成,让您能够将 Web 应用程序的请求与其对应的后端跟踪关联起来。这种组合使您能够一目了然地查看完整的前端和后端数据,实现端到端的性能监控和问题排查。
通过 Trace 追踪,您可以:
* **关联前后端请求**:将前端用户操作与后端 API 调用关联
* **端到端问题排查**:快速定位从前端到后端的完整请求链路问题
* **性能瓶颈分析**:识别整个请求链路中的性能瓶颈点
* **用户体验优化**:基于完整的请求链路数据优化用户体验
## 工作原理
Trace 追踪基于 [W3C Trace Context](https://www.w3.org/TR/trace-context/) 标准实现,通过在 HTTP 请求头中注入追踪信息来关联前后端请求:
RUM SDK 自动为配置的 API 请求添加追踪头信息
后端服务接收并处理带有追踪信息的请求
通过相同的 `trace_id` 将前后端数据关联起来
通过 trace 关联根据 `trace_id` 查看完整的请求链路信息
## 配置步骤
### 1. SDK 配置
首先需要在 RUM SDK 中配置分布式追踪功能。在初始化 RUM SDK 时添加以下参数:
```javascript theme={null}
import { flashcatRum } from "@flashcatcloud/browser-rum";
flashcatRum.init({
applicationId: "",
clientToken: "",
service: "",
env: "",
version: "1.0.0",
sessionSampleRate: 100,
allowedTracingUrls: [
"https://api.example.com",
/https:\/\/.*\.my-api-domain\.com/,
(url) => url.startsWith("https://api.example.com")
],
traceSampleRate: 20
});
```
#### 关键配置参数
指定需要添加追踪信息的 API 端点,支持以下类型:
| 类型 | 说明 | 示例 |
| --------- | ---------------------- | ---------------------------------------- |
| **字符串** | 匹配以该值开头的 URL | `"https://api.example.com"` |
| **正则表达式** | 使用正则表达式匹配 URL | `/https:\/\/.*\.my-api-domain\.com/` |
| **函数** | 自定义匹配逻辑,返回 `true` 表示匹配 | `(url) => url.startsWith("https://api")` |
追踪采样率,控制多少比例的请求会被追踪(范围 0-100)
生产环境建议将 `traceSampleRate` 设置为 10-20,以平衡监控覆盖率和性能影响。
### 2. 应用管理配置
SDK 配置完成后,可在应用详情的 **Link 集成** 页签中配置 trace 跳转:
1. 进入 **应用管理** 页面
2. 选择对应的 RUM 应用并打开 **Link 集成** 页签
3. 在 **Tracing** 卡片中填写链路追踪系统的跳转链接
4. 保存链接后开启 **Tracing** 开关
在配置的跳转链接中,系统会自动将 `${trace_id}` 替换为资源事件中的实际 trace\_id。内置 Tracing 仅在资源事件包含 `trace_id` 时展示。
### 3. 后端服务配置
为了完整支持分布式追踪,后端服务需要:
1. **接收追踪头信息**:处理 `traceparent` 和 `tracestate` 请求头
2. **传递追踪信息**:在调用其他服务时继续传递追踪头信息
3. **生成追踪数据**:将请求处理过程记录到追踪系统中
## 追踪头信息说明
RUM SDK 会在配置的请求中自动添加以下 HTTP 头信息:
### traceparent 头
```
traceparent: 00-00000000000000008448eb211c80319c-b7ad6b7169203331-01
```
格式:`[version]-[trace-id]-[parent-id]-[trace-flags]`
| 字段 | 说明 |
| ------------- | -------------------------------- |
| `version` | 当前为 `00` |
| `trace-id` | 128 位的 trace ID,16 进制处理后为 32 个字符 |
| `parent-id` | 64 位的 span ID,16 进制处理后为 16 个字符 |
| `trace-flags` | 采样标志,`01` 表示命中采样,`00` 表示非采样 |
### tracestate 头
```
tracestate: dd=s:1;o:rum
```
格式:`dd=s:[sampling-priority];o:[origin]`
| 字段 | 说明 |
| ------------------- | ------------------------- |
| `sampling-priority` | `1` 表示 trace 被采样 |
| `origin` | 始终为 `rum`,表示通过 RUM SDK 采集 |
## 使用场景
### 在 RUM 查看器中查看 Trace
配置完成后,包含 `trace_id` 的资源事件会显示 Tracing 跳转入口:
1. 进入 **RUM 查看器**
2. 筛选或打开包含 API 调用的资源事件
3. 在资源列表的 `trace_id` 列点击 trace 链接,或在事件详情右上角打开 **关联 Link**
4. 跳转至您的 trace 系统查看详细的请求链路
### 通过 trace\_id 查找资源
通过 `trace_id` 也可以在查看器中进行资源查找:
1. 在查看器搜索栏中输入 `trace_id`
2. 查看对应的资源和视图加载情况
3. 分析资源加载性能与后端 API 调用的关联关系
也可以通过在 URL 上拼接参数直接查询相应的 resource:
```
https://console.flashcat.cloud/rum/explorer?appid=${YOUR_APP_ID}&end=${END_TIME}&eventType=resource&queryStr=trace_id%3A${TRACE_ID}&start=${START_TIME}
```
其中 `start`、`end`、`appid` 均为选填参数,若不传则会复用当前 RUM 默认查询的应用和时间范围。
### 端到端问题排查
当用户报告性能问题或者异常时:
在 RUM 查看器中找到问题用户的会话
查看问题页面的 trace 信息
跳转到 trace 系统查看完整的请求链路
判断是前端问题、服务问题,还是网络问题
## 最佳实践
### 合理配置采样率
| 环境 | 建议采样率 | 说明 |
| -------- | ------ | ---------- |
| **开发环境** | 100% | 确保所有请求都被追踪 |
| **测试环境** | 50-80% | 平衡监控覆盖率和性能 |
| **生产环境** | 10-20% | 避免对性能造成影响 |
### 精确配置追踪 URL
精确匹配 API 端点:
```javascript theme={null}
allowedTracingUrls: [
"https://api.example.com/v1/",
"https://api.example.com/v2/"
]
```
过于宽泛的匹配可能包含不需要追踪的静态资源:
```javascript theme={null}
// 不推荐
allowedTracingUrls: [
"https://api.example.com"
]
```
### 跨域请求处理
如果您的 HTTP 请求涉及跨域问题,需要确保:
* 服务器配置了正确的 CORS 头信息
* 支持预检请求(Preflight Request)
* 允许 `traceparent` 和 `tracestate` 头信息
### 性能监控
* 定期检查 trace 采样率对应用性能的影响
* 监控追踪数据的存储和查询性能
* 根据业务需求调整追踪策略
## 常见问题
可能的原因包括:
* 请求 URL 不在 `allowedTracingUrls` 配置范围内
* 请求被 `traceSampleRate` 采样率过滤
* 请求在 SDK 初始化之前发起
* 跨域请求缺少必要的 CORS 配置
可以通过以下方式验证:
1. 在浏览器开发者工具中检查网络请求头
2. 确认请求包含 `traceparent` 和 `tracestate` 头信息
3. 在 RUM 查看器中查看是否有 trace 信息显示
## 注意事项
* **隐私合规**:确保 trace 数据收集符合相关隐私法规要求
* **性能影响**:合理设置采样率,避免对应用性能造成显著影响
* **数据安全**:避免在 trace 数据中包含敏感信息
* **跨域配置**:确保后端服务正确配置 CORS 以支持追踪头信息
# 理解 RUM 采样:机制、规则与最佳实践
Source: https://docs.flashduty.com/zh/rum/best-practices/sampling
深入理解 RUM 会话采样的工作原理,掌握采样率选择、动态调整与业务自定义采样的最佳实践。
采样决定了有多少真实用户数据会被采集上报。采样率设置过高会带来不必要的数据量与费用,设置过低则可能漏掉关键问题。本文介绍 RUM 采样的工作机制,并给出选择和动态管理采样率的最佳实践。
## 采样是什么
RUM SDK 通过 `sessionSampleRate` 参数控制采样,取值 0 到 100,表示**被采集的会话百分比**:
```js theme={null}
import { flashcatRum } from "@flashcatcloud/browser-rum";
flashcatRum.init({
applicationId: "",
clientToken: "",
sessionSampleRate: 20, // 采集 20% 的会话
sessionReplaySampleRate: 10, // 已采集会话中,再抽 10% 录制会话重放
});
```
被采样命中的会话会上报全部数据(页面浏览、资源、错误、用户行为等);未命中的会话不上报任何数据——**包括错误**。这是理解采样的第一个关键点:采样率 20% 意味着线上 80% 的用户出了错,您在平台上是看不到的。
`sessionReplaySampleRate` 是在已采集会话基础上的**二次抽样**:`sessionSampleRate: 20` 且 `sessionReplaySampleRate: 10` 时,实际有会话重放录制的会话占全部流量的 2%。
## 采样的工作规则
理解以下四条规则,可以避免绝大多数「为什么配了采样率但行为不符合预期」的困惑。
### 1. 以会话为单位,而不是用户或事件
采样判定发生在**会话开始时**:SDK 按 `sessionSampleRate` 的概率抛一次硬币,中签则整个会话完整上报,不中签则整个会话完全静默。不存在「一个会话里 20% 的事件被上报」这种情况——会话数据要么完整,要么没有。
同一个用户今天的会话可能中签、明天的会话可能不中签。默认的采样机制**不锚定具体用户**。
### 2. 判定结果在会话内粘滞
抽签结果会随会话状态持久化(Web 端存储在 Cookie 中)。会话在用户持续活跃时最长保持 4 小时,不活跃 15 分钟后过期;期间用户刷新页面、跳转页面都不会重新抽签。只有会话过期后产生新会话时,才会按当时的采样率重新判定。
这意味着修改采样率后,**新会话立即按新采样率判定,存量会话维持原判定直到自然过期**。这正是渐进放量的正确语义,但也意味着调整不是瞬时全量生效的。
### 3. 是概率,不是精确配额
每个会话的抽签相互独立,没有全局协调。采样率 20% 表示**期望值**是 20%:流量越大,实际采集比例越接近 20%(大数定律);流量较小时会有明显波动,100 个会话实际采到 13 个或 28 个都是正常的。
### 4. 采样率在初始化时固化
`sessionSampleRate` 在 `init()` 调用时确定,初始化后无法在运行时修改,页面生命周期内也不能二次 `init()`。想改变采样率,需要让下一次初始化(Web 端即下一次页面加载)拿到新的值——下文的动态调整方案正是围绕这一点展开。
## 如何选择采样率
| 场景 | 建议 |
| ---------- | ------------------------------------- |
| 测试 / 预发环境 | `sessionSampleRate: 100`,流量小,全量采集便于验证 |
| 生产环境(中小流量) | 50–100,优先保证问题可见性 |
| 生产环境(大流量) | 10–30,结合数据量与费用权衡 |
| 会话重放 | 通常 1–10,重放是 SDK 开销与数据量的主要来源 |
| 新版本发布期 | 临时调高(如 100),稳定后降回常规值 |
| 线上故障排查期 | 临时调至 100,尽可能多地捕捉现场 |
错误是低频事件。如果您的核心诉求是错误监控而非性能统计,宁可选择更高的采样率——性能指标 20% 的样本足够代表整体,而某个只影响 1% 用户的错误在 20% 采样下可能很久才出现一次。
## 最佳实践一:让采样率可以动态调整
采样率写死在代码里,意味着每次调整都要发版。推荐把采样率外置到您自己的配置中心,SDK 初始化时读取:
```js theme={null}
const CACHE_KEY = "rum-sample-rate";
// 1. 用本地缓存的值立即初始化,不阻塞 SDK 启动
const cached = Number(localStorage.getItem(CACHE_KEY));
const sampleRate = Number.isFinite(cached) && cached > 0 ? cached : 20;
flashcatRum.init({
// ...其他配置
sessionSampleRate: sampleRate,
});
// 2. 异步拉取最新值,供下一次页面加载使用
fetch("https://your-config-server.example.com/rum-config")
.then((res) => res.json())
.then(({ sessionSampleRate: latest }) => {
localStorage.setItem(CACHE_KEY, String(latest));
// 3. 采样率变化时结束当前会话,让新判定尽快生效
if (latest !== sampleRate) {
flashcatRum.stopSession();
}
})
.catch(() => {}); // 拉取失败时沿用缓存值,不影响采集
```
```kotlin theme={null}
val prefs = getSharedPreferences("rum_config", Context.MODE_PRIVATE)
// 1. 用本地缓存的值立即初始化,不阻塞 SDK 启动
val sampleRate = prefs.getFloat("session_sample_rate", 20f)
val rumConfig = RumConfiguration.Builder(applicationId)
.setSessionSampleRate(sampleRate)
.build()
Rum.enable(rumConfig)
// 2. 异步拉取最新值写入缓存,下次冷启动生效
CoroutineScope(Dispatchers.IO).launch {
runCatching { fetchRumConfig() } // 请求您自己的配置服务
.onSuccess { config ->
prefs.edit()
.putFloat("session_sample_rate", config.sessionSampleRate)
.apply()
} // 拉取失败时沿用缓存值,不影响采集
}
```
```swift theme={null}
let defaults = UserDefaults.standard
// 1. 用本地缓存的值立即初始化,不阻塞 SDK 启动
let sampleRate = defaults.object(forKey: "rumSessionSampleRate") as? Float ?? 20
var rumConfig = RUM.Configuration(applicationID: "")
rumConfig.sessionSampleRate = sampleRate
RUM.enable(with: rumConfig)
// 2. 异步拉取最新值写入缓存,下次冷启动生效
URLSession.shared.dataTask(with: configURL) { data, _, _ in
guard let data,
let config = try? JSONDecoder().decode(RumRemoteConfig.self, from: data)
else { return } // 拉取失败时沿用缓存值,不影响采集
defaults.set(config.sessionSampleRate, forKey: "rumSessionSampleRate")
}.resume()
```
三个要点:
1. **不要为等配置阻塞初始化**。同步等待配置接口会漏掉页面早期的数据,配置服务抖动还会拖垮 RUM 启动。正确姿势是「缓存值立即初始化 + 异步刷新缓存供下次使用」,新采样率晚一个页面周期生效完全可以接受。
2. **采样率变化时调用 `stopSession()`(仅 Web / 小程序)**。由于判定结果在会话内粘滞(规则 2),一个在 20% 时代未中签的用户,即使新页面以 100% 初始化,也会因为存量会话的旧判定而继续静默,最长持续 4 小时。`stopSession()` 会让当前会话立即过期,用户的下一次交互产生新会话并按新采样率重新抽签。注意这招在移动端无效:移动端采样率在初始化时就冻结在采样器里,`stopSession()` 之后的新会话仍按旧值抽签,新值默认要等下次冷启动重新初始化才生效。如需立即生效,参见下方[移动端进阶方案](#移动端进阶让新采样率立即生效)。
3. **拉取失败必须有兜底**。配置接口不可用时沿用缓存值或内置默认值,保证采集不中断。
`stopSession()` 会把一个用户的连续行为切分成两个会话,导致会话数轻微膨胀、会话时长统计断开。只在采样率确实变化时调用它,不要每次页面加载都调用。
### 移动端进阶:让新采样率立即生效
移动端 App 进程可能存活数天,"下次冷启动生效"在事故排查这类需要**立即全量采集**的场景下不够用。此时可以走完整重建路径:`stopInstance()` 停止当前 SDK 实例,再用新采样率重新初始化。要点是**拉到新配置时只记录、不立刻重建,等 App 回前台这类安静的生命周期点再执行**——在用户操作中途重建会切断当前视图和会话上下文。
```kotlin theme={null}
// 拉取到新配置时只记录待生效值,不立刻重建
fun onConfigFetched(latest: RumRemoteConfig) {
prefs.edit().putFloat("session_sample_rate", latest.sessionSampleRate).apply()
pendingSampleRate = latest.sessionSampleRate.takeIf { it != currentSampleRate }
}
// App 回前台这类安静时机再执行重建
ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
val newRate = pendingSampleRate ?: return
pendingSampleRate = null
Datadog.stopInstance() // 停止当前实例
Datadog.initialize(context, coreConfiguration, TrackingConsent.GRANTED)
val rumConfig = RumConfiguration.Builder(applicationId)
.setSessionSampleRate(newRate)
.build()
Rum.enable(rumConfig) // 启用过的其他产品(Logs、Trace 等)也要一并重新 enable
currentSampleRate = newRate
}
})
```
```swift theme={null}
// 拉取到新配置时只记录待生效值,不立刻重建
func onConfigFetched(_ latest: RumRemoteConfig) {
defaults.set(latest.sessionSampleRate, forKey: "rumSessionSampleRate")
pendingSampleRate = latest.sessionSampleRate != currentSampleRate
? latest.sessionSampleRate : nil
}
// App 回前台这类安静时机再执行重建
NotificationCenter.default.addObserver(
forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main
) { _ in
guard let newRate = pendingSampleRate else { return }
pendingSampleRate = nil
Datadog.stopInstance() // 停止当前实例
Datadog.initialize(with: coreConfiguration, trackingConsent: .granted)
var rumConfig = RUM.Configuration(applicationID: "")
rumConfig.sessionSampleRate = newRate
RUM.enable(with: rumConfig) // 启用过的其他产品(Logs、Trace 等)也要一并重新 enable
currentSampleRate = newRate
}
```
重建是有代价的进阶操作,上线前请确认以下风险:
* **时机敏感**:在用户操作中途重建会切断当前视图/会话上下文,把连续行为切成两段会话。务必挑安静的生命周期点执行(如上例的 App 回前台时),而不是配置一到就立刻重建。
* **数据丢失风险**:`stopInstance()` 时本地缓冲区中尚未上传的数据是否会被完整发送,需要在您的环境中实测验证。
* **重建负担**:同一实例上启用过的所有产品(RUM、Logs、Trace、Session Replay)以及视图追踪策略、网络拦截器都要重新注册,漏掉任何一块就是静默的采集降级。
* **适用边界**:建议仅用于"事故排查需要立即全量"这类场景;常规的采样率调整走"下次冷启动生效"即可,零风险。React Native 未暴露 `stopInstance`,只能下次启动生效。
## 最佳实践二:业务自定义采样
默认的随机抽签对所有用户一视同仁,但业务往往希望差异化:VIP 用户全量采集、灰度用户重点观察、出过错的用户下次必采。这时可以把**抽签逻辑从 SDK 挪到业务代码**:业务自行判定当前会话是否采样,SDK 的 `sessionSampleRate` 只传 `0` 或 `100`,退化为开关。
```js theme={null}
function decideSampling(user, config) {
// 优先级从高到低的短路规则
if (config.incidentMode) return true; // 故障排查模式:全量采集
if (user.isInternal || user.isBeta) return true; // 内部/灰度用户:必采
if (user.isVip) return true; // 重点用户:必采
if (localStorage.getItem("rum-had-error")) return true; // 上次出过错:必采
// 底座:按 userId 确定性哈希分桶
return hash(user.id + config.salt) % 100 < config.sampleRate;
}
const sampled = decideSampling(currentUser, cachedConfig);
flashcatRum.init({
// ...其他配置
sessionSampleRate: sampled ? 100 : 0,
});
```
```kotlin theme={null}
fun decideSampling(user: User, config: RumRemoteConfig): Boolean {
// 优先级从高到低的短路规则
if (config.incidentMode) return true // 故障排查模式:全量采集
if (user.isInternal || user.isBeta) return true // 内部/灰度用户:必采
if (user.isVip) return true // 重点用户:必采
if (prefs.getBoolean("rum_had_error", false)) return true // 上次出过错:必采
// 底座:按 userId 确定性哈希分桶
return hash(user.id + config.salt) % 100 < config.sampleRate
}
val sampled = decideSampling(currentUser, cachedConfig)
val rumConfig = RumConfiguration.Builder(applicationId)
.setSessionSampleRate(if (sampled) 100f else 0f)
.build()
Rum.enable(rumConfig)
```
```swift theme={null}
func decideSampling(user: User, config: RumRemoteConfig) -> Bool {
// 优先级从高到低的短路规则
if config.incidentMode { return true } // 故障排查模式:全量采集
if user.isInternal || user.isBeta { return true } // 内部/灰度用户:必采
if user.isVip { return true } // 重点用户:必采
if UserDefaults.standard.bool(forKey: "rumHadError") { return true } // 上次出过错:必采
// 底座:按 userId 确定性哈希分桶
return hash(user.id + config.salt) % 100 < config.sampleRate
}
let sampled = decideSampling(user: currentUser, config: cachedConfig)
var rumConfig = RUM.Configuration(applicationID: "")
rumConfig.sessionSampleRate = sampled ? 100 : 0
RUM.enable(with: rumConfig)
```
### 为什么用哈希分桶代替随机数
底座规则用 `hash(userId) % 100` 而不是 `Math.random()`,带来两个默认抽签没有的性质:
* **用户级稳定**:同一个用户的判定结果永远一致,您可以回答「用户 A 有没有数据」——中签用户的所有会话都在,未中签用户则明确没有。
* **放量单调**:采样率从 20% 调到 100% 时,原本中签的用户全部继续中签,新增的是纯增量,前后数据连续可对比。换一个 `salt` 即可整体重新洗牌。
### 注意事项
* **判定必须在会话内稳定**。如果用 `Math.random()` 每次页面加载现抽,同一会话内不同页面可能得出不同结果,而 SDK 只认会话首次判定——表现为「配了 100 却不上报」,非常难排查。确定性哈希天然规避这个问题。
* **规则变化时同样需要切换会话**。用户从「不采」桶进入「采」桶时,参照最佳实践一的做法:Web / 小程序在检测到本次判定与上次缓存的判定不同时调用一次 `stopSession()`;移动端默认下次冷启动生效,或参照进阶方案重建实例。
* **用 `sessionSampleRate: 0` 而不是跳过 `init()`**。跳过初始化会让业务代码里的 `addAction` / `addError` 等调用失效,到处判空很繁琐;传 0 让 SDK 正常初始化为静默状态,代码路径统一。
* **平台侧数据代表实际采集量**。自定义采样时,平台无法感知您的真实采样比例,看到的会话量即实际采集量,无法按采样率反推全量流量。如需估算全量,请在业务侧基于自己的采样规则换算。
## 各端支持情况
| 平台 | 采样率生效时机 | 让新采样率立即生效 |
| ------------- | ----------------- | --------------------------------------------------------------- |
| Web(浏览器) | 每次页面加载 `init()` 时 | 支持,调用 `stopSession()` |
| 微信小程序 | 每次冷启动 `init()` 时 | 支持,调用 `stopSession()` |
| iOS / Android | App 冷启动初始化时 | 默认下次冷启动生效;可通过 `stopInstance()` 重建立即生效(见[进阶方案](#移动端进阶让新采样率立即生效)) |
| React Native | App 冷启动初始化时 | 不支持,下次启动生效 |
移动端默认建议「启动时读缓存值初始化 + 异步拉取最新值存缓存」的策略,新采样率在下次冷启动生效;确需立即生效的场景(如事故排查),参照进阶方案在安静的生命周期点重建 SDK 实例。
## 常见问题
存量会话的判定结果是粘滞的(规则 2)。修改前未中签的会话会保持静默直到过期(不活跃 15 分钟或持续 4 小时)。如果使用了动态配置方案,请确认在采样率变化时调用了 `stopSession()`。
采样是独立概率抽签,不是配额(规则 3)。流量越大越接近设定值,小流量下波动是正常现象。如需要精确控制「哪些用户被采集」,请使用业务自定义采样的哈希分桶方案。
严格意义上的「只上报错误」做不到——视图(view)事件是会话的骨架,无法关闭。但可以做到非常接近,思路是两个相互独立的开关叠加使用:
* **采样率控制「哪些会话被采集」**:以会话为单位,未命中的会话连错误也不上报(规则 1)。所以不能靠调低采样率来省量,那会同步丢掉错误。
* **事件开关控制「每个会话采集哪些事件」**:`trackResources`、`trackLongTasks`、`trackUserInteractions`、`trackWebVitals` 与采样无关,对每一个被采集的会话都生效。
因此「尽量只看错误」的正确配置是:把 `sessionSampleRate` 开到 100 保证错误不漏,再用事件开关把非错误数据压下去。资源事件通常是数据量的大头,收敛它的收益最明显。
**不要直接设置 `trackResources: false`。** 浏览器端的 HTTP 5xx 和请求失败**不是**错误事件,而是带 `status_code` 的资源事件——RUM 的错误事件只来自 JS 运行时异常、`console.error`、浏览器 Report API 和手动 `addError`。关闭资源采集会让接口报错在平台上完全消失,而这往往正是您最想看的那类「错误」。
推荐的做法是保留资源采集,用 `beforeSend` 只丢弃成功的请求:
```js theme={null}
flashcatRum.init({
applicationId: "",
clientToken: "",
sessionSampleRate: 100, // 全量采集会话,保证错误不漏
trackResources: true, // 必须保持开启,否则接口报错不可见
trackLongTasks: false,
trackUserInteractions: false,
trackWebVitals: false,
beforeSend: (event) => {
// 资源事件只保留失败的请求,成功的直接丢弃,不占用数据量
if (event.type === "resource") {
const statusCode = event.resource.status_code;
return statusCode === 0 || statusCode >= 400;
}
return true;
},
});
```
使用前请了解这套配置的三个代价:
* **视图事件仍会上报**:每个页面至少一条,指标或事件计数变化时会节流更新,会话活跃期间每 5 分钟还有一次保活更新。这是无法消除的底噪,`beforeSend` 也无法丢弃视图事件。
* **错误现场只剩堆栈**:关闭 `trackUserInteractions` 后,您无法知道用户点了什么才触发的错误,排查效率会明显下降。
* **链路追踪请求不受资源开关影响**:命中 `allowedTracingUrls` 的请求即使关闭资源采集也仍会上报(标记为不索引,不计入数据量),因此流量并不会归零。
如果您的目标是「错误优先,但仍要保留现场」,更推荐业务自定义采样:把「上次出过错的用户」列为必采人群,用整会话的完整数据换更高的错误捕获率。
# SDK 开发者合规指南
Source: https://docs.flashduty.com/zh/rum/others/compliance-guide
Flashduty RUM SDK 的个人信息处理规则、权限说明、数据处理承诺,以及接入方完成隐私披露与延迟初始化的合规要求
本指南说明 Flashduty RUM SDK(以下简称"本 SDK")在您的 App 中处理个人信息的规则与承诺,并指导您满足《个人信息保护法》《App 违法违规收集使用个人信息行为认定方法》以及各应用市场的隐私合规要求。本指南聚焦 SDK 自身的处理规则;Flashduty 作为受托处理者的服务条款与数据安全约定,另见《[数据保护协议](/zh/compliance/data-security)》与 RUM《[数据安全](/zh/rum/others/data-security)》。
## 合规使用的两项关键要求
接入本 SDK 后,您作为 App 运营者需完成以下**两项**合规动作,缺一不可:
在 App 隐私政策中说明已集成本 SDK 及其收集的个人信息。详见 [隐私政策披露](#1-隐私政策披露)。
在用户同意隐私政策**之前**,不初始化本 SDK、不上报任何数据。详见 [延迟初始化](#2-延迟初始化)。
未完成上述动作即上线,可能导致 App 在应用市场审核或监管隐私合规检测中被判定为"违规收集使用个人信息"。本指南其余章节说明这两项要求背后的事实依据与具体落地步骤。
## 合规责任划分
本 SDK 作为嵌入您 App 的第三方组件运行,责任边界如下:
| 角色 | 主体 | 职责 |
| ------- | --------------------------- | ----------------------------------------- |
| 个人信息处理者 | **您(App 运营者)** | 就 App 整体的个人信息收集使用行为(含所集成的本 SDK)向用户披露并取得同意 |
| 受托处理者 | **北京快猫星云科技有限公司(Flashduty)** | 仅在为您提供应用性能监控(RUM)服务的必要范围内处理数据,不用于约定以外的目的 |
根据《个人信息保护法》第二十一条,您与 Flashduty 之间构成委托处理关系:处理的目的、方式及个人信息种类由您决定,Flashduty 仅按约定处理、采取必要措施保障信息安全,不超出约定范围使用,也不进行转委托。双方权利义务以《[数据保护协议](/zh/compliance/data-security)》为准。
## SDK 处理个人信息的情况
以下内容是您完成隐私政策披露的事实依据。
### 收集的个人信息
本 SDK 遵循"最小必要"原则,仅为实现崩溃分析、性能诊断与用户体验监控等功能而收集与之直接相关的信息,不收集与上述功能无关的个人信息。下表逐项列明所收集的信息类型、字段、目的与收集方式;除"应用运行信息"外,其余采集项均可通过配置关闭或脱敏(见 [数据处理规则与承诺](#数据处理规则与承诺))。
| 信息类型 | 具体字段 | 收集目的 | 收集方式 | 是否可关闭 |
| ------- | ------------------------------------------------ | ------------------ | --------------- | --------------- |
| 设备信息 | 设备型号、品牌、设备名称、CPU 架构、屏幕信息 | 区分机型上的崩溃与性能表现 | SDK 自动采集 | 否(基础信息) |
| 操作系统信息 | 系统名称、版本号 | 区分系统版本的兼容性与故障分布 | SDK 自动采集 | 否(基础信息) |
| 网络信息 | 网络连接状态、网络接口类型(Wi-Fi / 蜂窝网络 / 有线网络等)、上行/下行带宽、信号强度 | 分析网络环境对加载与请求耗时的影响 | SDK 自动采集 | 否(基础信息) |
| 应用运行信息 | 包名、版本号、构建号、运行环境、SDK 版本 | 关联问题与发布版本 | SDK 自动采集 | 否(必需) |
| 崩溃与日志信息 | 崩溃堆栈、错误信息、ANR、自定义日志 | 还原崩溃现场、定位缺陷 | 发生崩溃/错误或主动打点时采集 | 可(关闭错误追踪) |
| 行为与性能信息 | 页面访问路径与停留时长、用户操作、资源加载耗时、长任务、启动耗时 | 还原用户路径、分析性能瓶颈 | 用户交互/页面跳转时采集 | 可(关闭自动追踪或脱敏) |
| 会话标识 | SDK 随机生成的会话 ID(`session.id`) | 将同一会话内的事件关联起来,便于追溯 | SDK 自动生成 | 否(已匿名化) |
| 网络地址 | 上报来源 IP 所在的国家/地区 | 按地域统计性能与故障 | 服务端根据上报 IP 解析获得 | 可(关闭 IP / 地理位置) |
### 明确不收集的信息
为最小化隐私影响,本 SDK **不收集**以下信息,也**不申请**相关敏感权限:
* 设备唯一标识符:**IMEI、IDFA、IDFV、Android ID、MAC 地址、OAID** 等;
* 精确地理位置(GPS / 经纬度);
* 通讯录、短信、通话记录、相册、麦克风、相机内容;
* 已安装应用列表;
* SIM 运营商名称 / 运营商 ID(`simCarrierIdName` / `simCarrierId`),及 IMSI、SIM 序列号等电信标识;
* 手机号、身份证号等可直接识别身份的信息(除非您主动通过 API 传入,见下方说明)。
本 SDK 承诺不以隐蔽、误导、欺诈等方式收集上述信息,也不会读取或回传与监控功能无关的设备数据。
若您主动通过 `setUserInfo`(用户 ID、名称、邮箱)或自定义属性向 SDK 传入可识别身份的信息,这些信息将随事件上报。请确保此类收集已在隐私政策中说明并取得同意,并**避免传入敏感个人信息**。
### 申请的设备权限
本 SDK 遵循权限最小化原则,仅申请实现监控所必需的网络权限,不申请定位、相机、麦克风、通讯录、电话、存储等敏感权限,也不会在运行时向用户弹出敏感权限申请弹窗。
| 平台 | 权限 | 用途 | 是否必需 |
| ------- | ----------------------------------------- | ----------------- | ---- |
| Android | `android.permission.INTERNET` | 上报监控数据 | 必需 |
| Android | `android.permission.ACCESS_NETWORK_STATE` | 读取网络状态用于指标采集与上报策略 | 必需 |
| iOS | 无需声明额外权限 | 网络访问使用系统默认能力 | — |
### 数据处理规则与承诺
除按最小必要原则收集外,本 SDK 还提供以下数据处理机制与承诺,帮助您进一步控制采集范围、降低隐私风险:
本 SDK 仅采集实现监控所必需的信息。会话以随机 `session.id` 标识、默认不追踪用户身份,从而在保留趋势分析能力的同时实现数据匿名化。
您可对采集行为进行细粒度控制:
* **关闭自动追踪**:可关闭用户操作(Action)与页面访问(View)的自动采集,仅保留显式上报;
* **采样**:通过会话采样率降低采集与上报比例;
* **属性脱敏**:通过 `EventMapper` 在事件上报前修改或丢弃字段,移除可能包含的个人信息(如操作名、URL 中的个人信息);
* **操作名屏蔽**:启用 `enablePrivacyForActionName` 将未显式命名的操作名替换为占位符。
详见 RUM《[数据安全](/zh/rum/others/data-security)》。
可在应用的"用户数据收集"设置中关闭 IP 地址与地理位置(国家/城市)数据的收集,关闭后立即在服务端生效。
支持通过您自有的代理服务器转发全部 RUM 事件,使终端设备不直接与 Flashduty 通信,便于您统一管控外发流量。
当用户撤回同意、停止使用 SDK 或账户注销后,您可将同意状态切换为 `NOT_GRANTED` 立即停止采集;已上报数据由 Flashduty 按约定保留期到期后删除或匿名化。
## 接入方的合规义务
本节说明 [合规使用的两项关键要求](#合规使用的两项关键要求) 的具体做法。
### 1. 隐私政策披露
请您确保所开发或运营的 App 配备符合监管要求的《隐私政策》文本,并务必明确告知终端用户您的 App 已集成第三方 SDK 服务。您应在《隐私政策》中载明本 SDK 收集、使用个人信息的目的、方式与范围,并标明本 SDK 开发运营者名称(**北京快猫星云科技有限公司**)及其隐私政策链接。
您应在 App 登录注册页面及 App 首次运行时,通过弹窗、文本链接、附件等简洁明显且易于访问的方式,以清晰易懂的语言向用户告知《隐私政策》,由用户在充分知情的前提下作出自愿、明确的意思表示。涉及向第三方提供个人信息的,还应在"第三方 SDK 信息共享清单"中单独列明。
我们提供以下告知文案示例供您参考,您可以通过文字或表格方式向用户告知(表格形式可直接参考上文 [收集的个人信息](#收集的个人信息))。请您理解,SDK 不同版本所提供的功能服务及所需字段信息,可能因您的选择或配置不同而存在差异;因此,请您结合本指南及您实际接入、使用的 SDK 运行情况,向用户进行充分告知并取得用户同意。
```text 第三方 SDK 信息披露 theme={null}
SDK 名称:Flashduty RUM SDK
SDK 提供方:北京快猫星云科技有限公司
使用目的:应用崩溃分析、性能监控与用户体验诊断
收集的个人信息:设备信息(型号、品牌、操作系统及版本、CPU 架构)、
网络信息(网络状态、网络接口类型、上行/下行带宽、信号强度)、应用运行与崩溃日志信息、
应用使用过程中的页面访问与操作行为、随机生成的会话标识
官网:https://flashcat.cloud
隐私政策:https://docs.flashduty.com/zh/compliance/data-security
```
### 2. 延迟初始化
为满足法律法规及监管要求,请确保在**取得用户同意后再初始化本 SDK**。为避免在取得用户同意前提前启动 SDK 收集、使用用户个人信息,本 SDK 提供了延迟初始化的 API 接口与合规初始化技术方案——详细操作指引见 [Android SDK 接入](/zh/rum/sdk/android/sdk-integration) 与 [iOS SDK 接入](/zh/rum/sdk/ios/sdk-integration)。
具体要求如下:
1. **先授权,后初始化**:确保用户阅读 App 隐私政策并取得授权之后,再按 App 功能需要在合适时机调用初始化接口;若用户不同意《隐私政策》,则**不得调用初始化接口**。如以 `PENDING` / `.pending` 状态初始化,该调用仅完成初始化并将数据暂存于本地、**不向服务端发送任何个人信息**,待切换为已授权后才开始上报。
2. **同意前不申请权限、不采集上报**:请勿在用户同意隐私政策之前动态申请涉及用户个人信息的敏感设备权限;请勿在用户同意前私自采集和上报个人信息(尤其注意 **Android ID、OAID、IMEI、MAC 地址、硬件序列号、应用安装列表**等)。上述标识本 SDK 默认即不采集,详见 [明确不收集的信息](#明确不收集的信息)。
| 同意状态 | SDK 行为 | 场景 |
| ----------------------------------------- | ------------------ | ------- |
| Android `GRANTED` / iOS `.granted` | 采集并上报 | 用户已同意 |
| Android `NOT_GRANTED` / iOS `.notGranted` | 不采集任何数据 | 用户拒绝或撤回 |
| Android `PENDING` / iOS `.pending` | 采集但暂不上报,待切换为已授权后发送 | 等待用户确认 |
下面给出各端"延迟初始化 + 同意变更"的写法:
```kotlin Android (Kotlin) theme={null}
import com.datadog.android.Datadog
import com.datadog.android.privacy.TrackingConsent
// 用户同意前:以 PENDING 初始化(采集但不上报)
Datadog.initialize(this, configuration, TrackingConsent.PENDING)
// 用户同意后:开始上报
Datadog.setTrackingConsent(TrackingConsent.GRANTED)
// 用户撤回同意:停止采集
Datadog.setTrackingConsent(TrackingConsent.NOT_GRANTED)
```
```java Android (Java) theme={null}
import com.datadog.android.Datadog;
import com.datadog.android.privacy.TrackingConsent;
// 用户同意前:以 PENDING 初始化(采集但不上报)
Datadog.initialize(this, configuration, TrackingConsent.PENDING);
// 用户同意后:开始上报
Datadog.setTrackingConsent(TrackingConsent.GRANTED);
// 用户撤回同意:停止采集
Datadog.setTrackingConsent(TrackingConsent.NOT_GRANTED);
```
```swift iOS (Swift) theme={null}
import DatadogCore
// 用户同意前:以 .pending 初始化(采集但不上报)
Datadog.initialize(with: configuration, trackingConsent: .pending)
// 用户同意后:开始上报
Datadog.set(trackingConsent: .granted)
// 用户撤回同意:停止采集
Datadog.set(trackingConsent: .notGranted)
```
```objective-c iOS (Objective-C) theme={null}
@import DatadogObjc;
// 初始化方式见 iOS SDK 接入文档;同意状态变更如下:
// 用户同意后:开始上报
[DDDatadog setWithTrackingConsent:DDTrackingConsentGranted];
// 用户撤回同意:停止采集
[DDDatadog setWithTrackingConsent:DDTrackingConsentNotGranted];
```
上方仅演示延迟初始化所需的最小代码。各端完整的初始化参数、接入步骤与同意 API,请参考对应平台文档:
* Android:[SDK 接入](/zh/rum/sdk/android/sdk-integration) · [高级配置 · 用户跟踪同意](/zh/rum/sdk/android/advanced-config#用户跟踪同意)
* iOS:[SDK 接入](/zh/rum/sdk/ios/sdk-integration) · [高级配置](/zh/rum/sdk/ios/advanced-config)
## 数据存储与安全
本 SDK 采集的数据仅上报至您配置的 Flashduty 服务端,用于向您提供监控服务,**不与其他第三方共享**,**不用于**广告、用户画像或跨 App 追踪。在数据全生命周期中,Flashduty 采取以下措施保障安全:
* **传输安全**:所有上报数据经 HTTPS/TLS 加密传输;
* **存储安全**:数据存储于中国境内合规服务器,并实施加密、访问控制与安全审计;
* **保留与删除**:数据按约定保留期存储,超期后删除或匿名化;
* **跨境传输**:未经您明确同意或法律法规另有规定,不进行跨境传输。
完整的安全措施、保留期限与跨境传输约定,见《[数据保护协议](/zh/compliance/data-security)》与 RUM《[数据安全](/zh/rum/others/data-security)》。
## 合规接入清单
在 App 隐私政策中加入本 SDK 的名称、提供方、收集信息与使用目的。
确保用户同意前不初始化 SDK、不上报数据(或使用 `PENDING` 状态)。
将本指南的个人信息字段与目的登记到 App 第三方共享清单 / 备案材料中。
在 App 设置中提供撤回同意的途径,撤回后调用 `setTrackingConsent(NOT_GRANTED)`。
检查 `setUserInfo` 与自定义属性,确保不向 SDK 传入敏感个人信息。
## 联系我们
本 SDK 由**北京快猫星云科技有限公司**提供。如您对本 SDK 的个人信息处理规则有任何疑问、意见或投诉,或需行使数据主体相关权利,可通过以下方式联系我们:
扫码添加企业微信,获取一对一技术支持
扫码添加商务经理企业微信
登录控制台左下角,提交反馈建议
[support@flashcat.cloud](mailto:support@flashcat.cloud)
# RUM 数据收集机制
Source: https://docs.flashduty.com/zh/rum/others/data-collection
本文档详细介绍 Flashduty RUM 的数据收集机制,包括事件类型、属性、指标以及数据保留期等信息。
RUM Browser SDK 生成具有相关指标和属性的事件。每个 RUM 事件都具有所有默认属性,例如页面的 URL(`view_url`)和用户信息,如设备类型(`device_type`)和国家(`geo_country`)。
还有特定于给定事件类型的附加指标和属性。例如,`view_loading_time` 指标与视图事件相关联,而 `resource_method` 属性与资源事件相关联。
## 事件类型
| 事件类型 | 保留期 | 描述 |
| ------------- | ---- | ------------------------------------------------------------------------------------------ |
| **Session** | 30 天 | 用户会话在用户开始浏览网络应用程序时开始。它包含关于用户的高级信息(浏览器、设备、地理位置)。它聚合了用户旅程中收集的所有 RUM 事件,使用唯一的 `session_id` 属性 |
| **View** | 30 天 | 每次用户访问网络应用程序的页面时都会生成视图事件。当用户留在同一页面上时,资源、长任务、错误和操作事件都链接到相关的 RUM 视图,使用 `view_id` 属性 |
| **Resource** | 15 天 | 为网页上加载的图像、XHR、Fetch、CSS 或 JS 库生成资源事件。它包括详细的加载时间信息 |
| **Long Task** | 15 天 | 对于在浏览器中阻塞主线程超过 50 毫秒的任何任务,都会生成长任务事件 |
| **Error** | 30 天 | RUM 收集浏览器发出的每个前端错误 |
| **Action** | 30 天 | RUM 操作事件跟踪用户旅程中的用户交互,也可以手动发送以监控自定义用户操作 |
会话在 15 分钟不活动后重置。
### 事件层次关系
## 默认属性
所有 RUM 事件都包含以下默认属性:
| 属性 | 类型 | 描述 |
| ---------------- | --- | ------------------------------------------------------ |
| `date` | 整数 | 事件的时间戳(以毫秒为单位) |
| `type` | 字符串 | 事件的类型(例如,`session`、`view`、`resource`、`error`、`action`) |
| `service` | 字符串 | 生成此事件的服务名称 |
| `application_id` | 字符串 | 生成此事件的应用程序 ID |
| `session_id` | 字符串 | 会话 ID |
| `view_id` | 字符串 | 视图 ID |
| `action_id` | 字符串 | 用户操作 ID |
| `context` | 对象 | 用户定义的上下文 |
## 事件特定指标和属性
### 会话指标
| 指标 | 类型 | 描述 |
| ------------------------- | -- | -------------- |
| `session_duration` | 数字 | 会话持续时间(以毫秒为单位) |
| `session_view_count` | 数字 | 会话中的视图数 |
| `session_action_count` | 数字 | 会话中的用户操作数 |
| `session_error_count` | 数字 | 会话中的错误数 |
| `session_resource_count` | 数字 | 会话中的资源数 |
| `session_long_task_count` | 数字 | 会话中的长任务数 |
### 会话属性
| 属性 | 类型 | 描述 |
| ------------------------------- | --- | --------------------------- |
| `session_type` | 字符串 | 会话类型(例如,`user`、`synthetic`) |
| `session_has_replay` | 布尔值 | 是否启用了会话重放 |
| `session_is_active` | 布尔值 | 会话是否处于活动状态 |
| `session_initial_view_id` | 字符串 | 初始视图 ID |
| `session_initial_view_url` | 字符串 | 初始视图 URL |
| `session_initial_view_referrer` | 字符串 | 初始视图的引用 URL |
### 视图指标
| 指标 | 类型 | 描述 |
| ----------------------------- | -- | ---------------- |
| `view_loading_time` | 数字 | 视图加载时间(以毫秒为单位) |
| `view_first_contentful_paint` | 数字 | 首次内容绘制时间(以毫秒为单位) |
| `view_dom_interactive` | 数字 | DOM 交互时间(以毫秒为单位) |
| `view_dom_complete` | 数字 | DOM 完成时间(以毫秒为单位) |
| `view_load_event_end` | 数字 | 加载事件结束时间(以毫秒为单位) |
| `view_error_count` | 数字 | 视图中的错误数 |
| `view_resource_count` | 数字 | 视图中的资源数 |
| `view_long_task_count` | 数字 | 视图中的长任务数 |
| `view_action_count` | 数字 | 视图中的用户操作数 |
### 视图属性
| 属性 | 类型 | 描述 |
| --------------- | --- | --------- |
| `view_url` | 字符串 | 视图 URL |
| `view_referrer` | 字符串 | 视图的引用 URL |
| `view_name` | 字符串 | 视图名称 |
### 资源指标
| 指标 | 类型 | 描述 |
| ------------------------------ | -- | ---------------- |
| `resource_duration` | 数字 | 资源加载时间(以毫秒为单位) |
| `resource_size` | 数字 | 资源大小(以字节为单位) |
| `resource_connect_duration` | 数字 | 连接时间(以毫秒为单位) |
| `resource_ssl_duration` | 数字 | SSL 握手时间(以毫秒为单位) |
| `resource_dns_duration` | 数字 | DNS 查找时间(以毫秒为单位) |
| `resource_first_byte_duration` | 数字 | 首字节时间(以毫秒为单位) |
| `resource_download_duration` | 数字 | 下载时间(以毫秒为单位) |
### 资源属性
| 属性 | 类型 | 描述 |
| -------------------------- | --- | ---------------------------------------------------------------------------- |
| `resource_type` | 字符串 | 资源类型(`xhr`、`fetch`、`document`、`script`、`css`、`image`、`font`、`media`、`other`) |
| `resource_method` | 字符串 | HTTP 方法(例如,`GET`、`POST`) |
| `resource_status_code` | 数字 | HTTP 状态码 |
| `resource_url` | 字符串 | 资源 URL |
| `resource_provider_name` | 字符串 | 资源提供者名称 |
| `resource_provider_domain` | 字符串 | 资源提供者域名 |
| `resource_provider_type` | 字符串 | 资源提供者类型(`first-party`、`third-party`) |
### 长任务指标
| 指标 | 类型 | 描述 |
| -------------------- | -- | --------------- |
| `long_task_duration` | 数字 | 长任务持续时间(以毫秒为单位) |
### 错误指标
| 指标 | 类型 | 描述 |
| ------------- | -- | --- |
| `error_count` | 数字 | 错误数 |
### 错误属性
| 属性 | 类型 | 描述 |
| --------------- | --- | ------------------------------------------------------------ |
| `error_source` | 字符串 | 错误来源(`console`、`network`、`source`、`logger`、`agent`、`custom`) |
| `error_type` | 字符串 | 错误类型 |
| `error_message` | 字符串 | 错误消息 |
| `error_stack` | 字符串 | 错误堆栈跟踪 |
### 用户操作指标
| 指标 | 类型 | 描述 |
| ------------------------ | -- | ---------------- |
| `action_loading_time` | 数字 | 用户操作加载时间(以毫秒为单位) |
| `action_long_task_count` | 数字 | 用户操作中的长任务数 |
| `action_resource_count` | 数字 | 用户操作中的资源数 |
| `action_error_count` | 数字 | 用户操作中的错误数 |
### 用户操作属性
| 属性 | 类型 | 描述 |
| -------------------- | --- | --------------------------- |
| `action_id` | 字符串 | 用户操作 ID |
| `action_type` | 字符串 | 用户操作类型(例如,`click`、`custom`) |
| `action_target_name` | 字符串 | 用户操作目标名称 |
| `action_name` | 字符串 | 用户操作名称 |
# 数据安全
Source: https://docs.flashduty.com/zh/rum/others/data-security
了解 Flashduty RUM 的数据安全机制和最佳实践,确保用户数据的安全性和隐私保护。
真实用户监控(RUM)涉及从最终用户的浏览器和移动设备收集数据。为了保护用户隐私和确保数据安全,Flashduty 提供了多种配置选项和工具来管理数据收集、存储和访问。
## 隐私选项
浏览器 RUM 客户端令牌用于将最终用户浏览器的数据与 Flashduty 中的特定 RUM 应用程序匹配。它是未加密的,可以从应用程序的客户端看到。
虽然客户端令牌仅用于向 Flashduty 发送数据,不会造成数据泄露风险,但我们建议采取以下良好的令牌管理措施:
* 定期轮换客户端令牌,确保它只被您的应用程序使用
* 在捕获 RUM 数据时自动过滤掉机器人
**认证代理**:使用占位符字符串替代 `clientToken`,代理在将会话数据传递给 Flashduty 之前检查有效的用户信息,从而确认真实用户已登录并正在传输要监控的流量。
事件是用户与您的网站或应用程序特定元素的交互。事件可以通过 SDK 自动捕获或通过自定义操作发送。
您可以关闭用户交互和页面访问的自动追踪,只捕获您选择的交互。默认情况下,RUM 使用目标内容从 SDK 自动收集的操作生成操作名称,您可以使用任何给定名称显式覆盖此行为。
您可以通过自己的代理服务器传输所有 RUM 事件,这样最终用户设备就永远不会直接与 Flashduty 通信。
默认情况下,**不会追踪用户身份**。每个会话都有一个与之关联的唯一 `session.id`,这样可以匿名化数据,但允许您了解趋势。
您可以选择编写代码来捕获用户数据(如姓名和电子邮件地址),然后使用该数据来丰富和修改 RUM 会话,但这不是必需的。
## 数据保留
配置事件捕获后,事件将存储在 Flashduty 中。您可以决定捕获的事件和属性在 Flashduty 中保留多长时间。
**默认保留期:**
* 会话、视图、操作、错误和会话录制保留 **30 天**
* 资源和长任务保留 **15 天**
## 个人和敏感数据移除
您可以使用多个选项来移除个人身份信息(PII)和敏感数据,包括 IP 地址和地理位置信息。
RUM 中可能出现 PII 的场景包括:
* 按钮上的操作名称(例如"查看完整信用卡号码")
* URL 中显示的名称
* 应用程序开发人员设置的自定义追踪事件
结合使用 `enablePrivacyForActionName` 选项和 `mask` 隐私设置,可以自动将所有未被覆盖的操作名称替换为占位符 `Masked Element`。
此设置还设计为与现有的 HTML 覆盖属性兼容。
初始化 RUM 应用程序后,您可以在**用户数据收集**选项卡中选择是否要包含 IP 或地理位置数据。
禁用 IP 数据收集后,更改将立即生效。在禁用之前收集的任何事件不会删除 IP 数据。这是在后端执行的,浏览器 SDK 仍在发送数据,但 IP 地址在处理时会被 Flashduty 后端管道省略和丢弃。
除了删除客户端 IP 外,您还可以选择禁用从所有未来收集的数据中收集地理位置(国家、城市、县)或 GeoIP 信息。
如果取消选中**收集地理位置数据**框,更改将立即生效。在禁用之前收集的任何事件不会删除相应的地理位置数据。数据省略在后端级别完成。
# 术语说明
Source: https://docs.flashduty.com/zh/rum/others/glossary
本文档详细介绍 Flashduty RUM 中使用的关键术语和概念,帮助用户更好地理解和使用 RUM 功能。
## 核心概念
| 名称 | 说明 |
| ------------------ | -------------------------------------------------------------------- |
| **RUM(真实用户监控)** | RUM(Real User Monitor)通过收集和分析真实用户在使用网站或应用时的性能数据,帮助开发者了解实际用户体验,优化应用性能 |
| **Session(会话)** | 会话是 RUM 数据聚合的核心单位,用于分析用户旅程和体验 |
| **View(视图)** | 视图记录页面加载时间、资源请求等,核心于性能监控 |
| **Action(动作)** | 用于分析用户行为,衡量用户体验中的交互性能和挫折点(如 "rage clicks") |
| **Resource(资源)** | 分析资源加载时间和性能,优化页面加载速度 |
| **Error(错误)** | 用于监控前端稳定性,识别影响用户体验的错误 |
| **Long Task(长任务)** | RUM 捕获长任务以识别导致页面卡顿或用户体验不佳的性能瓶颈 |
| **Pageview(页面浏览)** | 页面浏览是 RUM 数据的基本单位,用于分析特定页面的性能 |
| **Issue** | Issue 是错误管理的核心,用于聚合同类错误,优先级排序问题,并结合上下文帮助开发者快速定位和修复问题 |
## 性能指标
| 名称 | 说明 |
| --------------------------- | ---------------------------------------------------- |
| **Core Web Vitals(核心网页指标)** | RUM 监控这些指标以评估网页加载和交互性能 |
| **LCP(最大内容绘制时间)** | Largest Contentful Paint,衡量页面加载性能,记录页面主要内容加载完成的时间 |
| **FID(首次输入延迟)** | First Input Delay,衡量页面交互性能,记录用户首次与页面交互到浏览器响应的延迟时间 |
| **CLS(累积布局偏移)** | Cumulative Layout Shift,衡量页面视觉稳定性,记录页面加载过程中发生的意外布局偏移 |
| **TTFB(首字节时间)** | Time to First Byte,衡量服务器响应速度,记录从请求发出到收到第一个字节的时间 |
## 数据分析
| 名称 | 说明 |
| ------------------------- | ---------------------------------- |
| **Facet(切面)** | 便于在 RUM Explorer 中构建查询,分析特定用户群体的行为 |
| **Attribute(属性)** | 提供上下文,增强数据分析的灵活性 |
| **Global Context(全局上下文)** | 增强 RUM 数据分析的定制化能力 |