From efaefa9bcd0051d6a49ba2f651c86d59faa484ab Mon Sep 17 00:00:00 2001 From: Fiona Date: Mon, 28 Sep 2026 00:21:46 -0700 Subject: [PATCH 01/36] docs(rum): bump Flutter SDK snippets to flashcat_flutter_plugin 0.2.0 Point the install snippets at the current pub.dev releases: flashcat_flutter_plugin ^0.2.0, flashcat_tracking_http_client ^0.1.2 and flashcat_webview_tracking ^0.1.1. The plugin moved to 0.2.0, which a ^0.1.x caret constraint does not admit, and the two add-on packages were republished to depend on it. --- en/rum/sdk/flutter/advanced-config.mdx | 4 ++-- en/rum/sdk/flutter/compatible.mdx | 2 +- en/rum/sdk/flutter/sdk-integration.mdx | 6 +++--- zh/rum/sdk/flutter/advanced-config.mdx | 4 ++-- zh/rum/sdk/flutter/compatible.mdx | 2 +- zh/rum/sdk/flutter/sdk-integration.mdx | 6 +++--- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/en/rum/sdk/flutter/advanced-config.mdx b/en/rum/sdk/flutter/advanced-config.mdx index a52b20ca0..5ccf977f9 100644 --- a/en/rum/sdk/flutter/advanced-config.mdx +++ b/en/rum/sdk/flutter/advanced-config.mdx @@ -95,9 +95,9 @@ When a Flutter screen embeds a WebView, use `flashcat_webview_tracking` to corre ```yaml pubspec.yaml dependencies: - flashcat_flutter_plugin: ^0.1.3 + flashcat_flutter_plugin: ^0.2.0 webview_flutter: ^4.0.4 - flashcat_webview_tracking: ^0.1.0 + flashcat_webview_tracking: ^0.1.1 ``` ```dart diff --git a/en/rum/sdk/flutter/compatible.mdx b/en/rum/sdk/flutter/compatible.mdx index 36a0cbf80..56a05b2d3 100644 --- a/en/rum/sdk/flutter/compatible.mdx +++ b/en/rum/sdk/flutter/compatible.mdx @@ -10,7 +10,7 @@ This page describes the Flutter SDK support scope and current limits so you can | Item | Support | |------|----------| -| SDK version | `flashcat_flutter_plugin` 0.1.3 | +| SDK version | `flashcat_flutter_plugin` 0.2.0 | | Target platforms | **iOS and Android** (Flutter Web / Desktop not supported) | | Flutter / Dart | Flutter ≥ 3.27.0, Dart ≥ 3.6.0 | | iOS | Deployment target ≥ 12.0 | diff --git a/en/rum/sdk/flutter/sdk-integration.mdx b/en/rum/sdk/flutter/sdk-integration.mdx index c636f28c3..366c64f0f 100644 --- a/en/rum/sdk/flutter/sdk-integration.mdx +++ b/en/rum/sdk/flutter/sdk-integration.mdx @@ -7,7 +7,7 @@ keywords: ["RUM", "Flutter SDK", "Dart", "user monitoring", "mobile monitoring"] The Flutter SDK wraps the native iOS / Android SDKs and provides RUM capabilities through `flashcat_flutter_plugin`. After initialization, the SDK reports the application's views, user actions, network requests, errors, and crashes to Flashduty RUM, with `source: "flutter"` identifying the data source. -The current SDK version is `0.1.3` and supports the **iOS and Android** platforms (Flutter Web is not supported). Dart class names begin with `Datadog*` (such as `DatadogSdk` and `DatadogConfiguration`), and the site enum is `FlashcatSite`. Logs, Session Replay, and the dio / gql / grpc interceptor packages are not supported. +The current SDK version is `0.2.0` and supports the **iOS and Android** platforms (Flutter Web is not supported). Dart class names begin with `Datadog*` (such as `DatadogSdk` and `DatadogConfiguration`), and the site enum is `FlashcatSite`. Logs, Session Replay, and the dio / gql / grpc interceptor packages are not supported. ## Prerequisites @@ -25,7 +25,7 @@ Add `flashcat_flutter_plugin` to `pubspec.yaml`, then run `flutter pub get`. ```yaml pubspec.yaml dependencies: - flashcat_flutter_plugin: ^0.1.3 + flashcat_flutter_plugin: ^0.2.0 ``` @@ -133,7 +133,7 @@ Automatic network collection is provided by the separate `flashcat_tracking_http ```yaml pubspec.yaml dependencies: - flashcat_tracking_http_client: ^0.1.1 + flashcat_tracking_http_client: ^0.1.2 ``` ```dart diff --git a/zh/rum/sdk/flutter/advanced-config.mdx b/zh/rum/sdk/flutter/advanced-config.mdx index 0b5e3f7ab..b8662d7fa 100644 --- a/zh/rum/sdk/flutter/advanced-config.mdx +++ b/zh/rum/sdk/flutter/advanced-config.mdx @@ -95,9 +95,9 @@ Flutter 页面内嵌 WebView 时,可通过 `flashcat_webview_tracking` 把 Web ```yaml pubspec.yaml dependencies: - flashcat_flutter_plugin: ^0.1.3 + flashcat_flutter_plugin: ^0.2.0 webview_flutter: ^4.0.4 - flashcat_webview_tracking: ^0.1.0 + flashcat_webview_tracking: ^0.1.1 ``` ```dart diff --git a/zh/rum/sdk/flutter/compatible.mdx b/zh/rum/sdk/flutter/compatible.mdx index d41c0dd2a..3fcaaeafd 100644 --- a/zh/rum/sdk/flutter/compatible.mdx +++ b/zh/rum/sdk/flutter/compatible.mdx @@ -10,7 +10,7 @@ keywords: ["RUM", "Flutter SDK", "兼容性", "Dart", "iOS", "Android"] | 项目 | 支持情况 | |------|----------| -| SDK 版本 | `flashcat_flutter_plugin` 0.1.3 | +| SDK 版本 | `flashcat_flutter_plugin` 0.2.0 | | 目标平台 | **iOS 和 Android**(不支持 Flutter Web / Desktop) | | Flutter / Dart | Flutter ≥ 3.27.0,Dart ≥ 3.6.0 | | iOS | 部署目标 ≥ 12.0 | diff --git a/zh/rum/sdk/flutter/sdk-integration.mdx b/zh/rum/sdk/flutter/sdk-integration.mdx index 48e258c72..4b34807f1 100644 --- a/zh/rum/sdk/flutter/sdk-integration.mdx +++ b/zh/rum/sdk/flutter/sdk-integration.mdx @@ -7,7 +7,7 @@ keywords: ["RUM", "Flutter SDK", "Dart", "用户监控", "移动端监控"] 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 拦截包。 +当前 SDK 版本为 `0.2.0`,支持 **iOS 和 Android** 平台(不支持 Flutter Web)。Dart 类名以 `Datadog*` 开头(如 `DatadogSdk`、`DatadogConfiguration`),站点枚举为 `FlashcatSite`。暂不支持 Logs、Session Replay,以及 dio / gql / grpc 拦截包。 ## 前提条件 @@ -25,7 +25,7 @@ Flutter SDK 基于原生 iOS / Android SDK 封装,通过 `flashcat_flutter_plu ```yaml pubspec.yaml dependencies: - flashcat_flutter_plugin: ^0.1.3 + flashcat_flutter_plugin: ^0.2.0 ``` @@ -133,7 +133,7 @@ DatadogSdk.instance.rum?.addAction(RumActionType.tap, 'Checkout'); ```yaml pubspec.yaml dependencies: - flashcat_tracking_http_client: ^0.1.1 + flashcat_tracking_http_client: ^0.1.2 ``` ```dart From d4616a9c5b53c7573ed2d2e8ae5d86452ff3dc56 Mon Sep 17 00:00:00 2001 From: Fiona Date: Mon, 28 Sep 2026 00:26:21 -0700 Subject: [PATCH 02/36] docs(rum): document remote configuration for Flutter flashcat_flutter_plugin 0.2.0 exposes the remote configuration channel of the native Android and iOS SDKs to Dart. Add a Remote configuration section to the Flutter advanced configuration page covering remoteConfigurationEnabled, getRemoteConfig(), beforeSampling, setForcedSession() and the add-to-app case, and list Flutter among the platforms the console's Remote Configuration tab supports. --- en/rum/quickstart/app-management.mdx | 4 +- en/rum/sdk/flutter/advanced-config.mdx | 59 +++++++++++++++++++++++++- zh/rum/quickstart/app-management.mdx | 4 +- zh/rum/sdk/flutter/advanced-config.mdx | 58 ++++++++++++++++++++++++- 4 files changed, 117 insertions(+), 8 deletions(-) diff --git a/en/rum/quickstart/app-management.mdx b/en/rum/quickstart/app-management.mdx index ca7a20b6c..182927be9 100644 --- a/en/rum/quickstart/app-management.mdx +++ b/en/rum/quickstart/app-management.mdx @@ -297,7 +297,7 @@ After disabling geo-location or IP address collection, the related filter and an The **Remote Configuration** tab lets you adjust collection and privacy parameters online, without code changes or a new release. When enabled, the configuration on this page overrides SDK initialization settings. When disabled, clients fall back to their SDK initialization settings and data collection continues uninterrupted. -- Remote Configuration is currently available for **Browser**, **iOS**, **Android** and **WeChat Mini Program** applications. Other platform types will be enabled as their SDKs ship support. +- Remote Configuration is currently available for **Browser**, **iOS**, **Android**, **Flutter** and **WeChat Mini Program** applications. Other platform types will be enabled as their SDKs ship support. - On SaaS the feature is rolled out account by account. If the **Remote Configuration** tab is not visible on the application detail page, contact support to enable it. On private deployments it is available by default. @@ -311,7 +311,7 @@ The **Remote Configuration** tab lets you adjust collection and privacy paramete | **Replay privacy level** | `mask` / `mask-user-input` / `allow` | Default masking of page content in Session Replay: `mask` obscures text and hides input values; `mask-user-input` keeps page text and hides only what users typed; `allow` records the page as it is. Loosening the level starts collecting content that was not collected before, and replays already uploaded cannot be retroactively masked. The console asks you to confirm again before publishing | | **Custom configuration keys** | Key–value pairs typed as string / number / boolean / JSON | Delivered to clients together with the remote configuration and read by your application code; the platform does not interpret them. Up to 5 keys; each key name is at most 64 bytes (counted in UTF-8, not characters), each value at most 4 KB and nesting at most 3 levels (objects and arrays each count one level), and all custom entries together at most 16 KB | -iOS, Android, and WeChat Mini Program applications also show the **Remote Configuration** tab, but their SDKs read only the **session sample rate** and **custom configuration keys** (none of the three has Session Replay; the other values are neither delivered nor effective). Every SDK has to opt in with `remoteConfigurationEnabled: true` at initialization (off by default; an application that has not opted in never requests the configuration). On iOS this requires SDK 0.6.0 or later, see [iOS SDK Advanced Configuration](/en/rum/sdk/ios/advanced-config#remote-configuration); on Android it requires SDK 0.7.0 or later, see [Android SDK Advanced Configuration](/en/rum/sdk/android/advanced-config#remote-configuration-adjust-the-sample-rate-from-the-console). +iOS, Android, Flutter, and WeChat Mini Program applications also show the **Remote Configuration** tab, but their SDKs read only the **session sample rate** and **custom configuration keys** (none of them has Session Replay; the other values are neither delivered nor effective). Every SDK has to opt in with `remoteConfigurationEnabled: true` at initialization (off by default; an application that has not opted in never requests the configuration). On iOS this requires SDK 0.6.0 or later, see [iOS SDK Advanced Configuration](/en/rum/sdk/ios/advanced-config#remote-configuration); on Android it requires SDK 0.7.0 or later, see [Android SDK Advanced Configuration](/en/rum/sdk/android/advanced-config#remote-configuration-adjust-the-sample-rate-from-the-console); on Flutter it requires `flashcat_flutter_plugin` 0.2.0 or later, see [Flutter SDK Advanced Configuration](/en/rum/sdk/flutter/advanced-config#remote-configuration). Custom entries are delivered to clients and may be readable by end users. Never put secrets, access tokens, or personally sensitive information in them. diff --git a/en/rum/sdk/flutter/advanced-config.mdx b/en/rum/sdk/flutter/advanced-config.mdx index a52b20ca0..c92f31365 100644 --- a/en/rum/sdk/flutter/advanced-config.mdx +++ b/en/rum/sdk/flutter/advanced-config.mdx @@ -1,7 +1,7 @@ --- title: "Flutter SDK advanced configuration" -description: "Configure sampling, tracking consent, event filtering, distributed tracing, and symbol file upload for the Flutter RUM SDK" -keywords: ["RUM", "Flutter SDK", "advanced configuration", "sampling", "tracking consent", "symbol upload"] +description: "Configure sampling, remote configuration, tracking consent, event filtering, distributed tracing, and symbol file upload for the Flutter RUM SDK" +keywords: ["RUM", "Flutter SDK", "advanced configuration", "sampling", "remote configuration", "tracking consent", "symbol upload"] --- This page describes the advanced configuration options of the Flutter SDK. All configuration is passed through `DatadogConfiguration` and `DatadogRumConfiguration`. @@ -16,6 +16,61 @@ DatadogRumConfiguration( ); ``` +## Remote configuration + +Starting with `flashcat_flutter_plugin` 0.2.0, the session sample rate can be adjusted online from the console under **Application Management > Remote Configuration**, with no code change or new release. The feature is off by default and has to be enabled at initialization: + +```dart +DatadogRumConfiguration( + applicationId: '', + sessionSamplingRate: 100.0, // Used when the console delivers no rate + remoteConfigurationEnabled: true, +); +``` + +Once enabled, the configuration is fetched by the native Android / iOS SDK underneath the plugin, and behaves exactly as it does there: + +- A rate published in the console applies to the **next new session**; a session already under way is not affected. +- The delivered values are persisted locally, so the first session after a cold start is already drawn under the last delivered rate. +- A failed, timed-out or unreadable response leaves the values in force untouched; they are never cleared. When remote configuration is disabled in the console, the SDK falls back to the `sessionSamplingRate` passed at initialization. +- The Flutter SDK reads only the **session sample rate** and **custom configuration keys**; the other settings have no effect. Read the custom keys with `getRemoteConfig()`, which returns `null` when remote configuration is off or no configuration has arrived yet: + +```dart +final custom = await DatadogSdk.instance.rum?.getRemoteConfig(); +// Numbers can arrive as int or double depending on the platform, so read them as num +final threshold = (custom?['threshold'] as num?)?.toDouble(); +``` + +To decide sampling by your own business rules, use the `beforeSampling` callback. Each time a new session is about to be drawn it receives the rate that would apply (`sessionSampleRate`) and the console's custom keys (`custom`); return a rate to override it, or `null` to leave it alone. It runs synchronously, so keep it fast; returning a value outside 0–100, throwing, or timing out all keep the native SDK's decision. The callback also runs when remote configuration is off — `sessionSampleRate` is then the local value and `custom` is `null`. + +```dart +DatadogRumConfiguration( + applicationId: '', + remoteConfigurationEnabled: true, + beforeSampling: (context) { + // For example: collect every session of users listed in the custom key debugUsers, + // and keep the delivered rate for everyone else + final debugUsers = context.custom?['debugUsers']; + if (debugUsers is List && debugUsers.contains(currentUserId)) { + return 100; + } + return null; + }, +); +``` + +To collect the current user regardless of the sample rate (for example while investigating one user's issue), call `DatadogSdk.instance.rum?.setForcedSession()`. If the current session was sampled out it ends immediately and a collected one starts; every session afterwards is collected for the lifetime of the process. The setting cannot be reverted until the app restarts. + + +When Flutter attaches to a native SDK that is already initialized (add-to-app), `remoteConfigurationEnabled` and `beforeSampling` must be set by the native side when it initializes RUM — see [iOS SDK Advanced Configuration](/en/rum/sdk/ios/advanced-config#remote-configuration) and [Android SDK Advanced Configuration](/en/rum/sdk/android/advanced-config#remote-configuration-adjust-the-sample-rate-from-the-console). `getRemoteConfig()` and `setForcedSession()` still work from Dart. + + + +Custom configuration keys are delivered to clients and readable by anyone who holds the Client Token. Never put secrets, access tokens, or personally sensitive information in them. + + +For the console side (settings, publishing and when a version takes effect), see [Application Management · Remote Configuration](/en/rum/quickstart/app-management#remote-configuration). + ## Tracking consent `TrackingConsent` controls whether data is collected and reported, to meet compliance requirements such as GDPR: diff --git a/zh/rum/quickstart/app-management.mdx b/zh/rum/quickstart/app-management.mdx index 096282c6e..8ff8bda83 100644 --- a/zh/rum/quickstart/app-management.mdx +++ b/zh/rum/quickstart/app-management.mdx @@ -298,7 +298,7 @@ Link 集成会从当前事件上下文中提取变量并替换到 URL 模板中 「远程配置」页签允许你在线调整采集与隐私参数,而无需改代码、重新发版。启用后,本页配置覆盖 SDK 初始化设置;停用后,各端恢复使用 SDK 初始化设置,数据采集不会停止。 -- 远程配置目前支持 **Browser**、**iOS**、**Android** 与**微信小程序**类型应用,其他平台类型将随各端 SDK 发布逐步开放。 +- 远程配置目前支持 **Browser**、**iOS**、**Android**、**Flutter** 与**微信小程序**类型应用,其他平台类型将随各端 SDK 发布逐步开放。 - SaaS 环境下该功能按账号逐步放量。如果应用详情页未显示「远程配置」页签,请联系支持团队开通;私有化部署默认可用。 @@ -312,7 +312,7 @@ Link 集成会从当前事件上下文中提取变量并替换到 URL 模板中 | **回放脱敏级别** | `mask` / `mask-user-input` / `allow` | 会话回放对页面内容的默认遮蔽程度:`mask` 遮蔽文本并隐藏输入值;`mask-user-input` 保留页面文本、仅隐藏用户输入;`allow` 按原样录制。放宽级别会开始录制此前未采集的内容,且已上传的回放无法事后补充脱敏,发布前系统会再次确认 | | **自定义配置项** | 键值对,类型支持字符串 / 数字 / 布尔值 / JSON | 随远程配置下发到客户端、由应用代码读取,平台不解析其内容。最多 5 个;键名最长 64 字节(按 UTF-8 计,非字符数),单个值最大 4 KB,JSON 值最多嵌套 3 层(对象、数组各计一层),全部自定义项合计最大 16 KB | -iOS、Android 与微信小程序应用同样展示「远程配置」页签,但这三端的 SDK 仅读取**会话采样率**与**自定义配置项**两项(三端均无 Session Replay,其余配置不下发也不生效)。各端 SDK 都需要在初始化时开启 `remoteConfigurationEnabled: true`(默认关闭,未开启的应用不会请求配置);iOS 端需要 SDK 0.6.0 及以上,接入方式见 [iOS SDK 高级配置](/zh/rum/sdk/ios/advanced-config);Android 端需要 SDK 0.7.0 及以上,接入方式见 [Android SDK 高级配置](/zh/rum/sdk/android/advanced-config)。 +iOS、Android、Flutter 与微信小程序应用同样展示「远程配置」页签,但这几端的 SDK 仅读取**会话采样率**与**自定义配置项**两项(均无 Session Replay,其余配置不下发也不生效)。各端 SDK 都需要在初始化时开启 `remoteConfigurationEnabled: true`(默认关闭,未开启的应用不会请求配置);iOS 端需要 SDK 0.6.0 及以上,接入方式见 [iOS SDK 高级配置](/zh/rum/sdk/ios/advanced-config);Android 端需要 SDK 0.7.0 及以上,接入方式见 [Android SDK 高级配置](/zh/rum/sdk/android/advanced-config);Flutter 端需要 `flashcat_flutter_plugin` 0.2.0 及以上,接入方式见 [Flutter SDK 高级配置](/zh/rum/sdk/flutter/advanced-config)。 自定义配置项会下发到客户端,可能被终端用户读取。请勿填写密钥、访问令牌或个人敏感信息。 diff --git a/zh/rum/sdk/flutter/advanced-config.mdx b/zh/rum/sdk/flutter/advanced-config.mdx index 0b5e3f7ab..f4af9f77c 100644 --- a/zh/rum/sdk/flutter/advanced-config.mdx +++ b/zh/rum/sdk/flutter/advanced-config.mdx @@ -1,7 +1,7 @@ --- title: "Flutter SDK 高级配置" -description: "配置 Flutter RUM SDK 的采样率、隐私同意、事件过滤、分布式追踪和符号文件上传" -keywords: ["RUM", "Flutter SDK", "高级配置", "采样", "隐私同意", "符号上传"] +description: "配置 Flutter RUM SDK 的采样率、远程配置、隐私同意、事件过滤、分布式追踪和符号文件上传" +keywords: ["RUM", "Flutter SDK", "高级配置", "采样", "远程配置", "隐私同意", "符号上传"] --- 本文介绍 Flutter SDK 的进阶配置项。所有配置都通过 `DatadogConfiguration` 与 `DatadogRumConfiguration` 传入。 @@ -16,6 +16,60 @@ DatadogRumConfiguration( ); ``` +## 远程配置 + +`flashcat_flutter_plugin` 0.2.0 起,会话采样率可以在控制台 **应用管理 > 远程配置** 页签在线调整,无需改代码、重新发版。该功能默认关闭,需要在初始化时开启: + +```dart +DatadogRumConfiguration( + applicationId: '', + sessionSamplingRate: 100.0, // 控制台未下发时使用的采样率 + remoteConfigurationEnabled: true, +); +``` + +开启后,配置由插件底层的原生 Android / iOS SDK 拉取,行为与原生端一致: + +- 控制台发布的采样率对**下一个新会话**生效,进行中的会话不受影响。 +- 下发的值会持久化到本地,冷启动后的第一个会话即按上次下发的采样率抽样。 +- 请求失败、超时或响应无法识别时,沿用已生效的值,不会清空;控制台停用远程配置后,恢复使用初始化时的 `sessionSamplingRate`。 +- Flutter SDK 只读取**会话采样率**与**自定义配置项**两项,其余配置项不生效。自定义配置项可通过 `getRemoteConfig()` 读取,未开启远程配置或尚未拿到配置时返回 `null`: + +```dart +final custom = await DatadogSdk.instance.rum?.getRemoteConfig(); +// 数字经平台通道传回时,可能是 int 也可能是 double(取决于平台),统一按 num 读取 +final threshold = (custom?['threshold'] as num?)?.toDouble(); +``` + +需要按业务规则决定采样时,可通过 `beforeSampling` 回调干预:每次新建会话时,它收到即将生效的采样率(`sessionSampleRate`)与控制台的自定义配置项(`custom`),返回新的采样率即可覆盖,返回 `null` 表示不干预。回调同步执行,需保持轻量;返回 0–100 以外的值、抛出异常或执行超时,都会沿用原生 SDK 的判定。未开启远程配置时回调同样会执行,此时 `sessionSampleRate` 是本地设置的值,`custom` 为 `null`。 + +```dart +DatadogRumConfiguration( + applicationId: '', + remoteConfigurationEnabled: true, + beforeSampling: (context) { + // 例如:控制台自定义配置项 debugUsers 里的用户全量采集,其余沿用下发的采样率 + final debugUsers = context.custom?['debugUsers']; + if (debugUsers is List && debugUsers.contains(currentUserId)) { + return 100; + } + return null; + }, +); +``` + +若要不受采样率限制地采集当前用户(例如排查特定用户的问题),可调用 `DatadogSdk.instance.rum?.setForcedSession()`:若当前会话未被采中,会立即结束并开启一个采集的新会话,此后直到进程结束的会话一律采集;该设置无法撤销,重启 App 后恢复。 + + +如果 Flutter 是挂接到一个已经初始化过的原生 SDK 上(add-to-app 场景),`remoteConfigurationEnabled` 与 `beforeSampling` 必须由原生侧在初始化 RUM 时配置,见 [iOS SDK 高级配置](/zh/rum/sdk/ios/advanced-config) 与 [Android SDK 高级配置](/zh/rum/sdk/android/advanced-config);`getRemoteConfig()` 与 `setForcedSession()` 仍可在 Dart 侧调用。 + + + +自定义配置项会下发到客户端,任何持有 Client Token 的人都能读到。请勿在其中存放密钥、访问令牌或个人敏感信息。 + + +控制台侧的配置项、发布与生效方式见 [应用管理 · 远程配置](/zh/rum/quickstart/app-management#远程配置)。 + ## 隐私同意 `TrackingConsent` 控制是否采集与上报数据,适配 GDPR 等合规要求: From b3a9098c789ba7996579dc6353e8516c8a65d1a1 Mon Sep 17 00:00:00 2001 From: Flashduty AI-SRE Date: Mon, 28 Sep 2026 08:08:10 +0000 Subject: [PATCH 03/36] =?UTF-8?q?docs:=20doc-review=202026-09-28=20(diff)?= =?UTF-8?q?=20=E2=80=94=20CLI=20incident=20projection=20fields=20and=20ale?= =?UTF-8?q?rt=20webhook=20detail=5Furl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - developer/cli: incident list / incident similar default structured projections now include num and detail_url (flashduty-cli internal/cli/incident.go) - on-call/integration/webhooks/alert-webhook: add the detail_url row to the Alert payload table (fc-event structs.AlertItem + logic.AlertDocToItem) --- en/developer/cli.mdx | 4 ++-- en/on-call/integration/webhooks/alert-webhook.mdx | 1 + zh/developer/cli.mdx | 4 ++-- zh/on-call/integration/webhooks/alert-webhook.mdx | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/en/developer/cli.mdx b/en/developer/cli.mdx index bc1353663..c59d6c161 100644 --- a/en/developer/cli.mdx +++ b/en/developer/cli.mdx @@ -842,8 +842,8 @@ The following commands support `--fields` with `json` or `toon` output. Supply c | Command | Structured output when `--fields` is omitted | Limit | | --- | --- | --- | -| `flashduty incident list` | `incident_id`, `title`, `incident_severity`, `progress`, `start_time`, `channel_id` | 16 KiB | -| `flashduty incident similar ` | `incident_id`, `title`, `incident_severity`, `progress`, `start_time`, `close_time`, `ack_time`, `alert_cnt`, `root_cause`, `score` | 16 KiB | +| `flashduty incident list` | `incident_id`, `num`, `title`, `incident_severity`, `progress`, `start_time`, `channel_id`, `detail_url` | 16 KiB | +| `flashduty incident similar ` | `incident_id`, `num`, `title`, `incident_severity`, `progress`, `start_time`, `close_time`, `ack_time`, `alert_cnt`, `root_cause`, `score`, `detail_url` | 16 KiB | | `flashduty incident detail ` | Returns full detail when `--fields` is omitted; otherwise returns only the selected fields | 8 KiB for projections only | | `flashduty alert-event list` | `event_id`, `alert_id`, `event_severity`, `event_status`, `event_time`, `title` | 16 KiB | | `flashduty channel escalate-rule-list ` | `rule_id`, `rule_name`, `status`, `priority`, `filters` | 16 KiB | diff --git a/en/on-call/integration/webhooks/alert-webhook.mdx b/en/on-call/integration/webhooks/alert-webhook.mdx index ec60001d3..4e1f7fff2 100644 --- a/en/on-call/integration/webhooks/alert-webhook.mdx +++ b/en/on-call/integration/webhooks/alert-webhook.mdx @@ -103,6 +103,7 @@ alt | string | Yes | Caption; may be an empty string | images | [][Image](#Image) | Yes | Alert image list; null when there are no images | | labels | map[string]string | No | Label KV, both Key and Value are strings | | event_cnt | int64 | No | Associated event count | +| detail_url | string | No | Console page for this alert, in the form `{console}/alert/detail/{alert_id}`; the field is omitted when the deployment has no console base configured | | incident | [Incident](#Incident) | No | Associated incident | diff --git a/zh/developer/cli.mdx b/zh/developer/cli.mdx index 4b0bc314a..5db54ea0d 100644 --- a/zh/developer/cli.mdx +++ b/zh/developer/cli.mdx @@ -842,8 +842,8 @@ TOON 不能直接用 `jq` 解析;需要管道给 `jq` 时请改用 `--json`。 | 命令 | 未指定 `--fields` 时的结构化输出 | 上限 | | --- | --- | --- | -| `flashduty incident list` | `incident_id`、`title`、`incident_severity`、`progress`、`start_time`、`channel_id` | 16 KiB | -| `flashduty incident similar ` | `incident_id`、`title`、`incident_severity`、`progress`、`start_time`、`close_time`、`ack_time`、`alert_cnt`、`root_cause`、`score` | 16 KiB | +| `flashduty incident list` | `incident_id`、`num`、`title`、`incident_severity`、`progress`、`start_time`、`channel_id`、`detail_url` | 16 KiB | +| `flashduty incident similar ` | `incident_id`、`num`、`title`、`incident_severity`、`progress`、`start_time`、`close_time`、`ack_time`、`alert_cnt`、`root_cause`、`score`、`detail_url` | 16 KiB | | `flashduty incident detail ` | 不指定 `--fields` 时返回完整详情;指定后只返回所选字段 | 仅投影输出为 8 KiB | | `flashduty alert-event list` | `event_id`、`alert_id`、`event_severity`、`event_status`、`event_time`、`title` | 16 KiB | | `flashduty channel escalate-rule-list ` | `rule_id`、`rule_name`、`status`、`priority`、`filters` | 16 KiB | diff --git a/zh/on-call/integration/webhooks/alert-webhook.mdx b/zh/on-call/integration/webhooks/alert-webhook.mdx index 705602d36..812e8ba4f 100644 --- a/zh/on-call/integration/webhooks/alert-webhook.mdx +++ b/zh/on-call/integration/webhooks/alert-webhook.mdx @@ -103,6 +103,7 @@ alt | string | 是 | 图片说明,可能为空字符串 | images | [][Image](#Image) | 是 | 告警图片列表,无图片时为 null| | labels | map[string]string | 否 | 标签 KV,Key 和 Value 均为字符串| | event_cnt | int64 | 否 | 关联事件个数| +| detail_url | string | 否 | 该告警在控制台的详情页地址,形如 `{控制台}/alert/detail/{alert_id}`;部署未配置控制台地址时该字段不返回 | | incident | [Incident](#Incident) | 否 | 所属故障| From a80d5f333d404064c86e16388ad4087a0a09b987 Mon Sep 17 00:00:00 2001 From: ysyneu Date: Mon, 28 Sep 2026 08:23:19 -0700 Subject: [PATCH 04/36] docs(change-integration): add GitHub change integration page Deployments, deployment statuses and releases from a GitHub webhook become Flashduty changes: one change per deployment id or release id, with the state-to-status mapping, ignored deliveries, labels and FAQ. Adds the zh/en pages, the navigation entries and the GithubChange in-app doc key. --- docs.json | 6 +- .../integration/change-integration/github.mdx | 131 ++++++++++++++++++ integration-docs/src/doc-map.mjs | 1 + .../integration/change-integration/github.mdx | 131 ++++++++++++++++++ 4 files changed, 267 insertions(+), 2 deletions(-) create mode 100644 en/on-call/integration/change-integration/github.mdx create mode 100644 zh/on-call/integration/change-integration/github.mdx diff --git a/docs.json b/docs.json index b7d93e9d8..37d503c6c 100644 --- a/docs.json +++ b/docs.json @@ -1774,7 +1774,8 @@ { "group": "变更集成", "pages": [ - "zh/on-call/integration/change-integration/custom-event" + "zh/on-call/integration/change-integration/custom-event", + "zh/on-call/integration/change-integration/github" ] }, { @@ -3172,7 +3173,8 @@ { "group": "Change Integration", "pages": [ - "en/on-call/integration/change-integration/custom-event" + "en/on-call/integration/change-integration/custom-event", + "en/on-call/integration/change-integration/github" ] }, { diff --git a/en/on-call/integration/change-integration/github.mdx b/en/on-call/integration/change-integration/github.mdx new file mode 100644 index 000000000..88c7dc198 --- /dev/null +++ b/en/on-call/integration/change-integration/github.mdx @@ -0,0 +1,131 @@ +--- +title: "GitHub change integration" +description: "Sync GitHub deployments and releases to Flashduty On-call through a GitHub webhook, as change events you can correlate with alerts and incidents." +keywords: ["change integration", "GitHub", "Deployment", "Release", "Webhook", "deployment events"] +--- + +**Plan requirement**: This feature requires an On-call Standard or higher subscription. [Learn more](https://flashcat.cloud/flashduty/price/) + +Use a GitHub repository or organization webhook to sync deployments and releases to Flashduty On-call. Each deployment and each release becomes one Flashduty change; every state of a deployment, from created and queued through running to success or failure, updates that same change. + +GitHub Actions jobs that declare an `environment` create deployments automatically, so repositories that release with Actions can connect without changing their workflows. + +
+ +## In Flashduty On-call +--- + +1. In the Flashduty console, go to **Integration Center → Change Events** +2. Select **GitHub** and enter an integration name +3. To assign changes to specific channels, add rules under the integration's **Routes** that match labels such as `repo` or `environment` +4. Click **Save** and copy the generated **Push URL** + +
+ +## Configure GitHub +--- + + + + +- Repository: go to the repository's **Settings → Webhooks** and click **Add webhook** +- Organization: go to the organization's **Settings → Webhooks** and click **Add webhook**; events from every repository in the organization are sent + +You need admin permission on the repository or organization. + + + + + +1. **Payload URL**: paste the complete Flashduty integration Push URL +2. **Content type**: select `application/json` (`application/x-www-form-urlencoded` is also accepted) +3. **Secret**: leave it empty; Flashduty authenticates the request by the `integration_key` in the Push URL + + + + + +1. Select **Let me select individual events** +2. Check **Deployments**, **Deployment statuses**, and **Releases**, and uncheck **Pushes**, which is selected by default +3. Keep **Active** checked and click **Add webhook** + +After you save, GitHub sends a `ping`. Flashduty accepts it without creating a change. + + + + +## What one change is +--- + +| GitHub object | Change key (change_key) | Notes | +|---|---|---| +| Deployment | `deployment:` | The `deployment` event and every `deployment_status` event of one deployment update the same change; two deployments of the same repository to the same environment are two changes | +| Release | `release:` | Publishing, unpublishing, and deleting one release update the same change | + +## Status mapping +--- + +| GitHub event | GitHub state | Flashduty change status | +|---|---|---| +| deployment | created | Ready | +| deployment_status | waiting (waiting for environment approval) | Planned | +| deployment_status | pending, queued | Ready | +| deployment_status | in_progress | Processing | +| deployment_status | success | Done | +| deployment_status | failure, error | Failed | +| release | published | Done | +| release | unpublished, deleted | Canceled | + +Done, Failed, and Canceled are end states; Flashduty records the change's end time when one arrives. + +These deliveries are accepted without creating a change: `ping`, any other event type, the release actions `created`, `edited`, `released`, and `prereleased` (GitHub also sends `published` when a release is published, and that is the one recorded), and the deployment state `inactive` (an older deployment replaced by a newer one; its earlier result stays as it was). + +## Change content +--- + +| Field | Deployment | Release | +|---|---|---| +| Title | `: deploy () to ` | `: release ` | +| Description | The deployment's description | The release name (empty when it equals the tag) | +| Link | The deployment log (`log_url` or `target_url`), or the repository's Deployments page when there is none | The release page | + +Labels can be used in routes and to filter the change list: + +| Label | Deployment | Release | +|---|---|---| +| `repo` | Full repository name, such as `octo-org/hello-world` | Same | +| `environment` | Deployment environment | — | +| `ref` | The branch, tag, or SHA deployed | The release's target branch or commit | +| `sha` | Full commit SHA deployed | — | +| `version` | — | Release tag | +| `task` | Deployment task, usually `deploy` | — | +| `actor` | The user who created the deployment | The release author | +| `deployment_id` / `release_id` | GitHub object ID | GitHub object ID | +| `state` | The latest GitHub deployment state | — | +| `prerelease` | — | `true` for a pre-release | + +## FAQ +--- + + + + +- Make sure the webhook has **Deployments** and **Deployment statuses** checked. **Pushes** alone creates no changes +- Check the delivery history and Flashduty's responses under **Recent Deliveries** on the GitHub webhook page +- Only releases that use GitHub Deployments send deployment events, for example a GitHub Actions job that declares an `environment`, or a call to the Deployments API + + + + + +No. An event with the same state and time is recorded once. + + + + + +- `unsupported deployment_status.state`: Flashduty received a deployment state it does not support yet. Contact us +- `deployment.id is missing` or `release.id is missing`: the payload is incomplete. Make sure the delivery comes from a native GitHub webhook + + + diff --git a/integration-docs/src/doc-map.mjs b/integration-docs/src/doc-map.mjs index 6f4a513ed..e581768e1 100644 --- a/integration-docs/src/doc-map.mjs +++ b/integration-docs/src/doc-map.mjs @@ -100,6 +100,7 @@ export const docMap = { Rizhiyi: `${alertBase}/rizhiyi.mdx`, CustomChange: `${integrationBase}/change-integration/custom-event.mdx`, + GithubChange: `${integrationBase}/change-integration/github.mdx`, Jira: { zh: 'legacy/zh/jira-change.md', en: 'legacy/en/jira-change.md', diff --git a/zh/on-call/integration/change-integration/github.mdx b/zh/on-call/integration/change-integration/github.mdx new file mode 100644 index 000000000..d3ab70521 --- /dev/null +++ b/zh/on-call/integration/change-integration/github.mdx @@ -0,0 +1,131 @@ +--- +title: "GitHub 变更集成" +description: "通过 GitHub Webhook 将 Deployment 部署和 Release 发布同步到 Flashduty On-call,作为变更事件与告警、故障关联。" +keywords: ["变更集成", "GitHub", "Deployment", "Release", "Webhook", "部署事件"] +--- + +**版本要求**:此功能需要 On-call 标准版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/) + +通过 GitHub 仓库或组织的 Webhook,将部署(Deployment)和发布(Release)同步到 Flashduty On-call。每一次部署、每一个 Release 对应一条 Flashduty 变更;部署从创建、排队、执行到成功或失败的每个状态,都会更新同一条变更。 + +GitHub Actions 中声明了 `environment` 的任务会自动创建 Deployment,因此使用 Actions 发布的仓库无需改动流水线即可接入。 + +
+ +## 在 Flashduty On-call +--- + +1. 进入 Flashduty 控制台,选择 **集成中心 → 变更事件** +2. 选择 **GitHub**,填写集成名称 +3. 如需把变更分派到指定协作空间,在集成的 **路由** 中按标签(例如 `repo`、`environment`)配置规则 +4. 点击 **保存**,复制生成的 **推送地址** + +
+ +## 在 GitHub 中配置 +--- + + + + +- 仓库级:进入仓库 **Settings → Webhooks**,点击 **Add webhook** +- 组织级:进入组织 **Settings → Webhooks**,点击 **Add webhook**,组织下所有仓库的事件都会推送 + +需要仓库或组织的管理员权限。 + + + + + +1. **Payload URL**:粘贴 Flashduty 集成的完整推送地址 +2. **Content type**:选择 `application/json`(选择 `application/x-www-form-urlencoded` 同样可以接收) +3. **Secret**:留空即可,Flashduty 通过推送地址中的 `integration_key` 鉴权 + + + + + +1. 选择 **Let me select individual events** +2. 勾选 **Deployments**、**Deployment statuses** 和 **Releases**,取消默认勾选的 **Pushes** +3. 保持 **Active** 勾选,点击 **Add webhook** + +保存后 GitHub 会发送一次 `ping`,Flashduty 返回成功但不会生成变更。 + + + + +## 一条变更是什么 +--- + +| GitHub 对象 | 变更标识(change_key) | 说明 | +|---|---|---| +| Deployment | `deployment:` | 同一次部署的 `deployment` 事件和所有 `deployment_status` 事件更新同一条变更;同一仓库、同一环境的两次部署是两条变更 | +| Release | `release:` | 发布、取消发布、删除同一个 Release 更新同一条变更 | + +## 状态映射 +--- + +| GitHub 事件 | GitHub 状态 | Flashduty 变更状态 | +|---|---|---| +| deployment | created | Ready | +| deployment_status | waiting(等待环境审批) | Planned | +| deployment_status | pending、queued | Ready | +| deployment_status | in_progress | Processing | +| deployment_status | success | Done | +| deployment_status | failure、error | Failed | +| release | published | Done | +| release | unpublished、deleted | Canceled | + +Done、Failed 和 Canceled 是结束状态,Flashduty 会记录变更结束时间。 + +以下推送返回成功但不生成变更:`ping`、未列出的其他事件类型、Release 的 `created`、`edited`、`released`、`prereleased` 动作(发布时 GitHub 会同时发送 `published`,以 `published` 为准)、部署状态 `inactive`(旧部署被新部署取代,不改变旧部署已有的结果)。 + +## 变更内容 +--- + +| 字段 | Deployment | Release | +|---|---|---| +| 标题 | `<仓库>: deploy (<短 SHA>) to <环境>` | `<仓库>: release ` | +| 描述 | Deployment 的 description | Release 名称(与 tag 相同时为空) | +| 链接 | 部署日志(`log_url` 或 `target_url`),没有时为仓库的 Deployments 页面 | Release 页面 | + +标签可用于路由和在变更列表中筛选: + +| 标签 | Deployment | Release | +|---|---|---| +| `repo` | 仓库全名,例如 `octo-org/hello-world` | 同左 | +| `environment` | 部署环境 | — | +| `ref` | 部署的分支、tag 或 SHA | Release 的目标分支或提交 | +| `sha` | 部署的完整提交 SHA | — | +| `version` | — | Release tag | +| `task` | Deployment task,通常为 `deploy` | — | +| `actor` | 创建部署的用户 | 发布者 | +| `deployment_id` / `release_id` | GitHub 对象 ID | GitHub 对象 ID | +| `state` | 最新的 GitHub 部署状态 | — | +| `prerelease` | — | 预发布时为 `true` | + +## 常见问题 +--- + + + + +- 确认 Webhook 勾选了 **Deployments** 和 **Deployment statuses**。只勾选 **Pushes** 时不会产生变更 +- 在 GitHub Webhook 页面的 **Recent Deliveries** 查看推送记录和 Flashduty 的响应 +- 只有使用 GitHub Deployments 的发布才会产生部署事件,例如在 GitHub Actions 任务中声明 `environment`,或调用 Deployments API + + + + + +不会。同一状态、同一时间的事件只记录一次。 + + + + + +- `unsupported deployment_status.state`:收到了 Flashduty 尚未支持的部署状态,请联系我们 +- `deployment.id is missing` 或 `release.id is missing`:推送内容不完整,请确认推送来自 GitHub 原生 Webhook + + + From c76e84be9b8272fc1e5534cc0893b7399d678395 Mon Sep 17 00:00:00 2001 From: ysyneu Date: Mon, 28 Sep 2026 08:35:36 -0700 Subject: [PATCH 05/36] docs(change): document the Failed change status change_status now accepts Failed. Like Done and Canceled it is a terminal status: the event time is recorded as the change end time. Update the standard change event docs, the change search view, and the change_status enum in the OpenAPI specs. --- api-reference/on-call.openapi.en.json | 10 ++++++---- api-reference/on-call.openapi.zh.json | 10 ++++++---- api-reference/openapi.en.json | 10 ++++++---- api-reference/openapi.legacy.zh.json | 6 ++++-- api-reference/openapi.zh.json | 10 ++++++---- en/on-call/incident/search-view-incident.mdx | 2 +- .../integration/change-integration/custom-event.mdx | 6 +++--- zh/on-call/incident/search-view-incident.mdx | 2 +- .../integration/change-integration/custom-event.mdx | 6 +++--- 9 files changed, 36 insertions(+), 26 deletions(-) diff --git a/api-reference/on-call.openapi.en.json b/api-reference/on-call.openapi.en.json index a76fc6d4a..53f4b9b57 100644 --- a/api-reference/on-call.openapi.en.json +++ b/api-reference/on-call.openapi.en.json @@ -30374,13 +30374,14 @@ }, "change_status": { "type": "string", - "description": "Lifecycle status of the change event, reported by the change source as execution progresses.\n| Value | Meaning |\n|---|---|\n| `Planned` | Planned, not started. |\n| `Ready` | Ready for execution. |\n| `Processing` | Being executed. |\n| `Canceled` | Canceled. |\n| `Done` | Completed. |", + "description": "Lifecycle status of the change event, reported by the change source as execution progresses.\n| Value | Meaning |\n|---|---|\n| `Planned` | Planned, not started. |\n| `Ready` | Ready for execution. |\n| `Processing` | Being executed. |\n| `Canceled` | Canceled. |\n| `Done` | Completed. |\n| `Failed` | Failed. |", "enum": [ "Planned", "Ready", "Processing", "Canceled", - "Done" + "Done", + "Failed" ] }, "link": { @@ -30468,13 +30469,14 @@ }, "change_status": { "type": "string", - "description": "Current lifecycle status of the change.\n| Value | Meaning |\n|---|---|\n| `Planned` | Planned, not started. |\n| `Ready` | Ready for execution. |\n| `Processing` | Being executed. |\n| `Canceled` | Canceled. |\n| `Done` | Completed. |", + "description": "Current lifecycle status of the change.\n| Value | Meaning |\n|---|---|\n| `Planned` | Planned, not started. |\n| `Ready` | Ready for execution. |\n| `Processing` | Being executed. |\n| `Canceled` | Canceled. |\n| `Done` | Completed. |\n| `Failed` | Failed. |", "enum": [ "Planned", "Ready", "Processing", "Canceled", - "Done" + "Done", + "Failed" ] }, "start_time": { diff --git a/api-reference/on-call.openapi.zh.json b/api-reference/on-call.openapi.zh.json index 3d49ef29d..6ffe7dad0 100644 --- a/api-reference/on-call.openapi.zh.json +++ b/api-reference/on-call.openapi.zh.json @@ -30374,13 +30374,14 @@ }, "change_status": { "type": "string", - "description": "变更事件的生命周期状态。由变更事件源按执行进度上报。\n| 值 | 含义 |\n|---|---|\n| `Planned` | 已计划,尚未开始。 |\n| `Ready` | 已就绪,待执行。 |\n| `Processing` | 正在执行。 |\n| `Canceled` | 已取消。 |\n| `Done` | 已完成。 |", + "description": "变更事件的生命周期状态。由变更事件源按执行进度上报。\n| 值 | 含义 |\n|---|---|\n| `Planned` | 已计划,尚未开始。 |\n| `Ready` | 已就绪,待执行。 |\n| `Processing` | 正在执行。 |\n| `Canceled` | 已取消。 |\n| `Done` | 已完成。 |\n| `Failed` | 失败。 |", "enum": [ "Planned", "Ready", "Processing", "Canceled", - "Done" + "Done", + "Failed" ] }, "link": { @@ -30468,13 +30469,14 @@ }, "change_status": { "type": "string", - "description": "变更的当前生命周期状态。\n| 取值 | 含义 |\n|---|---|\n| `Planned` | 已计划,未开始。 |\n| `Ready` | 就绪,待执行。 |\n| `Processing` | 执行中。 |\n| `Canceled` | 已取消。 |\n| `Done` | 已完成。 |", + "description": "变更的当前生命周期状态。\n| 取值 | 含义 |\n|---|---|\n| `Planned` | 已计划,未开始。 |\n| `Ready` | 就绪,待执行。 |\n| `Processing` | 执行中。 |\n| `Canceled` | 已取消。 |\n| `Done` | 已完成。 |\n| `Failed` | 失败。 |", "enum": [ "Planned", "Ready", "Processing", "Canceled", - "Done" + "Done", + "Failed" ] }, "start_time": { diff --git a/api-reference/openapi.en.json b/api-reference/openapi.en.json index 36e2edaf6..ea38f102a 100644 --- a/api-reference/openapi.en.json +++ b/api-reference/openapi.en.json @@ -4494,13 +4494,14 @@ "type": "string" }, "change_status": { - "description": "Lifecycle status of the change event, reported by the change source as execution progresses.\n| Value | Meaning |\n|---|---|\n| `Planned` | Planned, not started. |\n| `Ready` | Ready for execution. |\n| `Processing` | Being executed. |\n| `Canceled` | Canceled. |\n| `Done` | Completed. |", + "description": "Lifecycle status of the change event, reported by the change source as execution progresses.\n| Value | Meaning |\n|---|---|\n| `Planned` | Planned, not started. |\n| `Ready` | Ready for execution. |\n| `Processing` | Being executed. |\n| `Canceled` | Canceled. |\n| `Done` | Completed. |\n| `Failed` | Failed. |", "enum": [ "Planned", "Ready", "Processing", "Canceled", - "Done" + "Done", + "Failed" ], "type": "string" }, @@ -4576,13 +4577,14 @@ "type": "string" }, "change_status": { - "description": "Current lifecycle status of the change.\n| Value | Meaning |\n|---|---|\n| `Planned` | Planned, not started. |\n| `Ready` | Ready for execution. |\n| `Processing` | Being executed. |\n| `Canceled` | Canceled. |\n| `Done` | Completed. |", + "description": "Current lifecycle status of the change.\n| Value | Meaning |\n|---|---|\n| `Planned` | Planned, not started. |\n| `Ready` | Ready for execution. |\n| `Processing` | Being executed. |\n| `Canceled` | Canceled. |\n| `Done` | Completed. |\n| `Failed` | Failed. |", "enum": [ "Planned", "Ready", "Processing", "Canceled", - "Done" + "Done", + "Failed" ], "type": "string" }, diff --git a/api-reference/openapi.legacy.zh.json b/api-reference/openapi.legacy.zh.json index 8a655bf64..174469636 100644 --- a/api-reference/openapi.legacy.zh.json +++ b/api-reference/openapi.legacy.zh.json @@ -28938,7 +28938,8 @@ "Ready", "Processing", "Canceled", - "Done" + "Done", + "Failed" ] }, "start_time": { @@ -29007,7 +29008,8 @@ "Ready", "Processing", "Canceled", - "Done" + "Done", + "Failed" ], "description": "变更状态" }, diff --git a/api-reference/openapi.zh.json b/api-reference/openapi.zh.json index 25cbdfae4..770ca7810 100644 --- a/api-reference/openapi.zh.json +++ b/api-reference/openapi.zh.json @@ -4494,13 +4494,14 @@ "type": "string" }, "change_status": { - "description": "变更事件的生命周期状态。由变更事件源按执行进度上报。\n| 值 | 含义 |\n|---|---|\n| `Planned` | 已计划,尚未开始。 |\n| `Ready` | 已就绪,待执行。 |\n| `Processing` | 正在执行。 |\n| `Canceled` | 已取消。 |\n| `Done` | 已完成。 |", + "description": "变更事件的生命周期状态。由变更事件源按执行进度上报。\n| 值 | 含义 |\n|---|---|\n| `Planned` | 已计划,尚未开始。 |\n| `Ready` | 已就绪,待执行。 |\n| `Processing` | 正在执行。 |\n| `Canceled` | 已取消。 |\n| `Done` | 已完成。 |\n| `Failed` | 失败。 |", "enum": [ "Planned", "Ready", "Processing", "Canceled", - "Done" + "Done", + "Failed" ], "type": "string" }, @@ -4576,13 +4577,14 @@ "type": "string" }, "change_status": { - "description": "变更的当前生命周期状态。\n| 取值 | 含义 |\n|---|---|\n| `Planned` | 已计划,未开始。 |\n| `Ready` | 就绪,待执行。 |\n| `Processing` | 执行中。 |\n| `Canceled` | 已取消。 |\n| `Done` | 已完成。 |", + "description": "变更的当前生命周期状态。\n| 取值 | 含义 |\n|---|---|\n| `Planned` | 已计划,未开始。 |\n| `Ready` | 就绪,待执行。 |\n| `Processing` | 执行中。 |\n| `Canceled` | 已取消。 |\n| `Done` | 已完成。 |\n| `Failed` | 失败。 |", "enum": [ "Planned", "Ready", "Processing", "Canceled", - "Done" + "Done", + "Failed" ], "type": "string" }, diff --git a/en/on-call/incident/search-view-incident.mdx b/en/on-call/incident/search-view-incident.mdx index 177078103..8d4be9e38 100644 --- a/en/on-call/incident/search-view-incident.mdx +++ b/en/on-call/incident/search-view-incident.mdx @@ -277,7 +277,7 @@ The change event list displays the following information: | Column | Description | | :--- | :--- | -| **Status** | Current status of the change event, including Planned, Ready, Processing, Canceled, Done | +| **Status** | Current status of the change event, including Planned, Ready, Processing, Canceled, Done, Failed | | **Change Key** | Unique identifier of the change event | | **Title** | Brief description of the change event | | **Description** | Detailed information about the change event | diff --git a/en/on-call/integration/change-integration/custom-event.mdx b/en/on-call/integration/change-integration/custom-event.mdx index 2c57529f7..0896d868e 100644 --- a/en/on-call/integration/change-integration/custom-event.mdx +++ b/en/on-call/integration/change-integration/custom-event.mdx @@ -61,14 +61,14 @@ Use the **push URL** shown on the integration details page. The URL format is: | :--- | :---: | :--- | :--- | | title | Yes | string | Change title, such as a release title, ticket title, or deployment task name. | | change_key | Yes | string | Change identifier. Events with the same `change_key` are treated as the same change. Subsequent events update the change status, labels, and link. | -| change_status | Yes | string | Change status. Enum values are case-sensitive: `Planned`, `Ready`, `Processing`, `Canceled`, and `Done`. | +| change_status | Yes | string | Change status. Enum values are case-sensitive: `Planned`, `Ready`, `Processing`, `Canceled`, `Done`, and `Failed`. | | event_time | No | integer | Event occurrence time as a Unix timestamp. Seconds and milliseconds are both supported. If omitted, Flashduty uses the time when the event is received. | | description | No | string | Change description, such as change content, impact scope, execution steps, or rollback plan. | | link | No | string | Change details link, such as a release, ticket, or CI/CD task URL. | | labels | No | map | Change labels. Both keys and values must be strings. We recommend following the Prometheus label naming convention for keys. Flashduty replaces special characters such as spaces, dots, and slashes in label keys with underscores. | -When `change_status` is `Done` or `Canceled`, Flashduty records the event time as the change end time. If you report a non-terminal status again, the end time is cleared. +When `change_status` is `Done`, `Canceled`, or `Failed`, Flashduty records the event time as the change end time. If you report a non-terminal status again, the end time is cleared. ### Response @@ -151,7 +151,7 @@ Labels describe events and should be as rich as possible: - **Change scope**: such as host, cluster, etc. - **Change ownership**: such as team, owner, etc. -- **Change lifecycle**: use the same `change_key` to report different `change_status` values as the change moves through planned, processing, completed, or canceled states. This helps restore the change process on the incident timeline. +- **Change lifecycle**: use the same `change_key` to report different `change_status` values as the change moves through planned, processing, completed, canceled, or failed states. This helps restore the change process on the incident timeline. ## FAQ diff --git a/zh/on-call/incident/search-view-incident.mdx b/zh/on-call/incident/search-view-incident.mdx index 8b9541d2c..b0e70f781 100644 --- a/zh/on-call/incident/search-view-incident.mdx +++ b/zh/on-call/incident/search-view-incident.mdx @@ -278,7 +278,7 @@ AI SRE 代某位成员执行的动作(例如[自动化规则](/zh/ai-sre/autom | 列 | 说明 | | :--- | :--- | -| **状态** | 变更事件的当前状态,包括已提单、即将开始、进行中、已取消、已完成 | +| **状态** | 变更事件的当前状态,包括已提单、即将开始、进行中、已取消、已完成、失败 | | **Change Key** | 变更事件的唯一标识 | | **标题** | 变更事件的简要描述 | | **描述** | 变更事件的详细说明 | diff --git a/zh/on-call/integration/change-integration/custom-event.mdx b/zh/on-call/integration/change-integration/custom-event.mdx index 5c9b08801..892016f2b 100644 --- a/zh/on-call/integration/change-integration/custom-event.mdx +++ b/zh/on-call/integration/change-integration/custom-event.mdx @@ -62,14 +62,14 @@ POST, Content-Type: application/json | :--- | :---: | :--- | :--- | | title | 是 | string | 变更标题,例如发布单标题、工单标题或部署任务名称。 | | change_key | 是 | string | 变更标识。相同 `change_key` 会被识别为同一个变更,后续事件会更新该变更的状态、标签和链接。 | -| change_status | 是 | string | 变更状态。枚举值(首字母大写):`Planned` 计划中、`Ready` 待执行、`Processing` 执行中、`Canceled` 已取消、`Done` 已完成。 | +| change_status | 是 | string | 变更状态。枚举值(首字母大写):`Planned` 计划中、`Ready` 待执行、`Processing` 执行中、`Canceled` 已取消、`Done` 已完成、`Failed` 失败。 | | event_time | 否 | integer | 事件发生时间,Unix 时间戳。支持秒级或毫秒级时间戳;未传时使用 Flashduty 接收事件的时间。 | | description | 否 | string | 变更描述,例如变更内容、影响范围、执行步骤或回滚方案。 | | link | 否 | string | 变更详情链接,例如发布单、工单或 CI/CD 任务地址。 | | labels | 否 | map | 变更标签集合,key 和 value 均为 string 类型。建议 key 遵循 Prometheus 标签命名规范;系统会将 key 中的空格、点号、斜杠等特殊字符替换为下划线。 | -当 `change_status` 为 `Done` 或 `Canceled` 时,Flashduty 会将该事件时间记录为变更结束时间;再次上报非结束状态时,结束时间会被清空。 +当 `change_status` 为 `Done`、`Canceled` 或 `Failed` 时,Flashduty 会将该事件时间记录为变更结束时间;再次上报非结束状态时,结束时间会被清空。 ### 请求响应 @@ -152,7 +152,7 @@ curl -X POST '{api_host}/event/push/change/standard?integration_key={integration - **变更的应用范围**:如 host、cluster 等 - **变更的归属信息**:如 team、owner 等 -- **变更的生命周期**:同一个变更在计划、执行、完成或取消时,使用相同 `change_key` 持续上报不同 `change_status`,便于在故障时间线上还原变更过程 +- **变更的生命周期**:同一个变更在计划、执行、完成、取消或失败时,使用相同 `change_key` 持续上报不同 `change_status`,便于在故障时间线上还原变更过程 ## 常见问题 From 616caeb440c0f9141010eb28d121dd2069e68ab7 Mon Sep 17 00:00:00 2001 From: ysyneu Date: Mon, 28 Sep 2026 09:49:41 -0700 Subject: [PATCH 06/36] docs(change): add GitLab change integration page Documents the GitLab deployment change integration: webhook setup with Deployment events, deployment status mapping, what one change is, labels and FAQ. --- docs.json | 6 +- .../integration/change-integration/gitlab.mdx | 133 ++++++++++++++++++ integration-docs/src/doc-map.mjs | 1 + .../integration/change-integration/gitlab.mdx | 133 ++++++++++++++++++ 4 files changed, 271 insertions(+), 2 deletions(-) create mode 100644 en/on-call/integration/change-integration/gitlab.mdx create mode 100644 zh/on-call/integration/change-integration/gitlab.mdx diff --git a/docs.json b/docs.json index 37d503c6c..f67c81fa7 100644 --- a/docs.json +++ b/docs.json @@ -1775,7 +1775,8 @@ "group": "变更集成", "pages": [ "zh/on-call/integration/change-integration/custom-event", - "zh/on-call/integration/change-integration/github" + "zh/on-call/integration/change-integration/github", + "zh/on-call/integration/change-integration/gitlab" ] }, { @@ -3174,7 +3175,8 @@ "group": "Change Integration", "pages": [ "en/on-call/integration/change-integration/custom-event", - "en/on-call/integration/change-integration/github" + "en/on-call/integration/change-integration/github", + "en/on-call/integration/change-integration/gitlab" ] }, { diff --git a/en/on-call/integration/change-integration/gitlab.mdx b/en/on-call/integration/change-integration/gitlab.mdx new file mode 100644 index 000000000..7c67c1556 --- /dev/null +++ b/en/on-call/integration/change-integration/gitlab.mdx @@ -0,0 +1,133 @@ +--- +title: "GitLab change integration" +description: "Sync GitLab deployments to Flashduty On-call through a GitLab webhook, as change events you can correlate with alerts and incidents." +keywords: ["change integration", "GitLab", "Deployment", "Webhook", "deployment events"] +--- + +**Plan requirement**: This feature requires an On-call Standard or higher subscription. [Learn more](https://flashcat.cloud/flashduty/price/) + +Use a GitLab project or group webhook to sync deployments to Flashduty On-call. Each deployment becomes one Flashduty change; every state of a deployment, from waiting for approval through running to success, failure or cancellation, updates that same change. + +GitLab CI/CD jobs that declare an `environment` create deployments automatically, so projects that release with GitLab CI/CD can connect without changing their pipelines. This works for both GitLab.com and self-managed GitLab. + +
+ +## In Flashduty On-call +--- + +1. In the Flashduty console, go to **Integration Center → Change Events** +2. Select **GitLab** and enter an integration name +3. To assign changes to specific channels, add rules under the integration's **Routes** that match labels such as `project` or `environment` +4. Click **Save** and copy the generated **Push URL** + +
+ +## Configure GitLab +--- + + + + +- Project: go to the project's **Settings → Webhooks** and click **Add new webhook** +- Group (GitLab Premium or higher): go to the group's **Settings → Webhooks** and click **Add new webhook**; deployments from every project in the group are sent + +Project webhooks need the Maintainer or Owner role on the project; group webhooks need the Owner role on the group. + + + + + +1. **URL**: paste the complete Flashduty integration Push URL +2. **Signing token** and **Secret token**: not needed; Flashduty authenticates the request with the `integration_key` in the Push URL + + + + + +1. Under **Trigger**, select only **Deployment events** and clear the default **Push events** +2. Keep **Enable SSL verification** selected and click **Add webhook** + +GitLab's **Test** feature cannot send deployment events. Other events sent with Test (such as Push events) get a success response from Flashduty but create no change. + + + + +## What one change is +--- + +| GitLab object | Change identifier (change_key) | Notes | +|---|---|---| +| Deployment | `deployment:` | Every Deployment event of one deployment updates the same change; two deployments of the same project to the same environment (including a retried deploy job) are two changes | + +`deployment_id` is unique within one GitLab instance. To connect several GitLab instances (for example GitLab.com and a self-managed instance), create one integration per instance. + +## Status mapping +--- + +| GitLab deployment status | Flashduty change status | +|---|---| +| blocked (waiting for approval or a manual action) | Planned | +| created | Ready | +| running | Processing | +| success | Done | +| failed | Failed | +| canceled, skipped | Canceled | + +Done, Failed and Canceled are end states; Flashduty records the change's end time. GitLab only sends events for blocked, running, success, failed and canceled. + +These deliveries get a success response but create no change: event types other than Deployment (Push, Pipeline and so on), and the protected-environment approval events `approved` and `rejected`. An approval event describes the approval record, not the deployment itself: after an approval GitLab sends `running` when the deployment starts, and after a rejection it sends `failed`; the change status follows those deployment events. + +## Change content +--- + +| Field | Content | +|---|---| +| Title | `: deploy () to ` | +| Description | The title of the deployed commit (`commit_title`) | +| Link | The CI/CD job that ran the deployment; deployments created through the API or by a trigger job have no job, so the link is the project's Environments page | + +Labels can be used for routing and for filtering the change list: + +| Label | Content | +|---|---| +| `project` | Full project path, for example `acme/order-service` | +| `project_id` | GitLab project ID | +| `environment` | Deployment environment | +| `environment_tier` | Environment tier, for example `production` or `staging` | +| `ref` | Deployed branch or tag | +| `sha` | Short SHA of the deployed commit | +| `actor` | Username of the user who triggered the deployment | +| `deployment_id` | GitLab deployment ID | +| `state` | Latest GitLab deployment status | + +## FAQ +--- + + + + +- Make sure the webhook has **Deployment events** selected. With only **Push events** selected, no changes are created +- Check the deliveries and Flashduty's responses under **Recent events** on the GitLab webhook edit page +- Only GitLab deployments produce deployment events, for example a CI/CD job that declares an `environment`, or a call to the Deployments API + + + + + +No. An event with the same status and the same time is recorded only once. + + + + + +After a deployment is rejected, GitLab sends `failed`; Flashduty records the deployment status as Failed, with the `state` label set to `failed`. + + + + + +- `unsupported deployment status`: Flashduty received a deployment status it does not support yet; contact us +- `deployment_id is missing`: the payload is incomplete; make sure it comes from a native GitLab webhook + + + diff --git a/integration-docs/src/doc-map.mjs b/integration-docs/src/doc-map.mjs index e581768e1..c8eee5cc5 100644 --- a/integration-docs/src/doc-map.mjs +++ b/integration-docs/src/doc-map.mjs @@ -101,6 +101,7 @@ export const docMap = { CustomChange: `${integrationBase}/change-integration/custom-event.mdx`, GithubChange: `${integrationBase}/change-integration/github.mdx`, + GitlabChange: `${integrationBase}/change-integration/gitlab.mdx`, Jira: { zh: 'legacy/zh/jira-change.md', en: 'legacy/en/jira-change.md', diff --git a/zh/on-call/integration/change-integration/gitlab.mdx b/zh/on-call/integration/change-integration/gitlab.mdx new file mode 100644 index 000000000..35041c70c --- /dev/null +++ b/zh/on-call/integration/change-integration/gitlab.mdx @@ -0,0 +1,133 @@ +--- +title: "GitLab 变更集成" +description: "通过 GitLab Webhook 将部署(Deployment)同步到 Flashduty On-call,作为变更事件与告警、故障关联。" +keywords: ["变更集成", "GitLab", "Deployment", "Webhook", "部署事件"] +--- + +**版本要求**:此功能需要 On-call 标准版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/) + +通过 GitLab 项目或群组的 Webhook,将部署(Deployment)同步到 Flashduty On-call。每一次部署对应一条 Flashduty 变更;部署从等待审批、执行到成功、失败或取消的每个状态,都会更新同一条变更。 + +GitLab CI/CD 中声明了 `environment` 的任务会自动创建部署,因此使用 GitLab CI/CD 发布的项目无需改动流水线即可接入。GitLab.com 和自托管 GitLab 均适用。 + +
+ +## 在 Flashduty On-call +--- + +1. 进入 Flashduty 控制台,选择 **集成中心 → 变更事件** +2. 选择 **GitLab**,填写集成名称 +3. 如需把变更分派到指定协作空间,在集成的 **路由** 中按标签(例如 `project`、`environment`)配置规则 +4. 点击 **保存**,复制生成的 **推送地址** + +
+ +## 在 GitLab 中配置 +--- + + + + +- 项目级:进入项目 **Settings → Webhooks**,点击 **Add new webhook** +- 群组级(GitLab Premium 及以上):进入群组 **Settings → Webhooks**,点击 **Add new webhook**,群组下所有项目的部署都会推送 + +项目级需要项目的 Maintainer 或 Owner 角色,群组级需要群组的 Owner 角色。 + + + + + +1. **URL**:粘贴 Flashduty 集成的完整推送地址 +2. **Signing token** 和 **Secret token**:无需配置,Flashduty 通过推送地址中的 `integration_key` 鉴权 + + + + + +1. 在 **Trigger** 中只勾选 **Deployment events**,取消默认勾选的 **Push events** +2. 保持 **Enable SSL verification** 勾选,点击 **Add webhook** + +GitLab 的 **Test** 功能不能发送部署事件;用 Test 发送的其他事件(例如 Push events)Flashduty 返回成功但不会生成变更。 + + + + +## 一条变更是什么 +--- + +| GitLab 对象 | 变更标识(change_key) | 说明 | +|---|---|---| +| Deployment | `deployment:` | 同一次部署的所有 Deployment 事件更新同一条变更;同一项目、同一环境的两次部署(包括重试部署任务)是两条变更 | + +`deployment_id` 在同一个 GitLab 实例内唯一。如果要接入多个 GitLab 实例(例如 GitLab.com 和自托管实例),请为每个实例创建一个集成。 + +## 状态映射 +--- + +| GitLab 部署状态 | Flashduty 变更状态 | +|---|---| +| blocked(等待审批或手动操作) | Planned | +| created | Ready | +| running | Processing | +| success | Done | +| failed | Failed | +| canceled、skipped | Canceled | + +Done、Failed 和 Canceled 是结束状态,Flashduty 会记录变更结束时间。GitLab 实际只在 blocked、running、success、failed、canceled 时推送事件。 + +以下推送返回成功但不生成变更:Deployment 以外的事件类型(Push、Pipeline 等)、受保护环境的审批事件 `approved` 和 `rejected`。审批事件描述的是审批记录而不是部署本身:批准后 GitLab 会在部署开始时推送 `running`,拒绝后会推送 `failed`,变更状态以这些部署事件为准。 + +## 变更内容 +--- + +| 字段 | 内容 | +|---|---| +| 标题 | `<项目>: deploy (<短 SHA>) to <环境>` | +| 描述 | 部署提交的标题(`commit_title`) | +| 链接 | 执行部署的 CI/CD 任务页面;通过 API 或 trigger 任务创建的部署没有任务,链接为项目的 Environments 页面 | + +标签可用于路由和在变更列表中筛选: + +| 标签 | 内容 | +|---|---| +| `project` | 项目完整路径,例如 `acme/order-service` | +| `project_id` | GitLab 项目 ID | +| `environment` | 部署环境 | +| `environment_tier` | 环境层级,例如 `production`、`staging` | +| `ref` | 部署的分支或 tag | +| `sha` | 部署提交的短 SHA | +| `actor` | 触发部署的用户名 | +| `deployment_id` | GitLab 部署 ID | +| `state` | 最新的 GitLab 部署状态 | + +## 常见问题 +--- + + + + +- 确认 Webhook 勾选了 **Deployment events**。只勾选 **Push events** 时不会产生变更 +- 在 GitLab Webhook 编辑页的 **Recent events** 查看推送记录和 Flashduty 的响应 +- 只有 GitLab 部署才会产生部署事件,例如在 CI/CD 任务中声明 `environment`,或调用 Deployments API + + + + + +不会。同一状态、同一时间的事件只记录一次。 + + + + + +是的。GitLab 拒绝部署后会推送 `failed`,Flashduty 按部署状态记录为 Failed,标签 `state` 为 `failed`。 + + + + + +- `unsupported deployment status`:收到了 Flashduty 尚未支持的部署状态,请联系我们 +- `deployment_id is missing`:推送内容不完整,请确认推送来自 GitLab 原生 Webhook + + + From 5395913ab1885560c1f15f2ae958eb6b0b532096 Mon Sep 17 00:00:00 2001 From: ysyneu Date: Mon, 28 Sep 2026 09:49:56 -0700 Subject: [PATCH 07/36] docs(change): add LaunchDarkly change integration page --- docs.json | 6 +- .../change-integration/launchdarkly.mdx | 139 ++++++++++++++++++ integration-docs/src/doc-map.mjs | 1 + .../change-integration/launchdarkly.mdx | 139 ++++++++++++++++++ 4 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 en/on-call/integration/change-integration/launchdarkly.mdx create mode 100644 zh/on-call/integration/change-integration/launchdarkly.mdx diff --git a/docs.json b/docs.json index 37d503c6c..7888aac2d 100644 --- a/docs.json +++ b/docs.json @@ -1775,7 +1775,8 @@ "group": "变更集成", "pages": [ "zh/on-call/integration/change-integration/custom-event", - "zh/on-call/integration/change-integration/github" + "zh/on-call/integration/change-integration/github", + "zh/on-call/integration/change-integration/launchdarkly" ] }, { @@ -3174,7 +3175,8 @@ "group": "Change Integration", "pages": [ "en/on-call/integration/change-integration/custom-event", - "en/on-call/integration/change-integration/github" + "en/on-call/integration/change-integration/github", + "en/on-call/integration/change-integration/launchdarkly" ] }, { diff --git a/en/on-call/integration/change-integration/launchdarkly.mdx b/en/on-call/integration/change-integration/launchdarkly.mdx new file mode 100644 index 000000000..31272e9a4 --- /dev/null +++ b/en/on-call/integration/change-integration/launchdarkly.mdx @@ -0,0 +1,139 @@ +--- +title: "LaunchDarkly change integration" +description: "Sync LaunchDarkly feature flag and segment changes to Flashduty On-call through a LaunchDarkly webhook, as change events you can correlate with alerts and incidents." +keywords: ["change integration", "LaunchDarkly", "Feature Flag", "feature flag", "Webhook"] +--- + +**Plan requirement**: This feature requires an On-call Standard or higher subscription. [Learn more](https://flashcat.cloud/flashduty/price/) + +Use a LaunchDarkly organization webhook to sync feature flag and segment changes to Flashduty On-call. Each flag or segment entry in LaunchDarkly's change history becomes one Flashduty change, for example turning a flag on or off, editing targeting rules, or changing the default rule. + +LaunchDarkly sends changes that have already taken effect, so each change is recorded as **Done** directly. + +
+ +## In Flashduty On-call +--- + +1. In the Flashduty console, go to **Integration Center → Change Events** +2. Select **LaunchDarkly** and enter an integration name +3. To assign changes to specific channels, add rules under the integration's **Routes** that match labels such as `project`, `environment`, or `flag` +4. Click **Save** and copy the generated **Push URL** + +
+ +## Configure LaunchDarkly +--- + + + + +1. Click the **gear** icon in the left sidebar to open **Organization settings** +2. Click **Integrations**, find **Webhooks**, and click **Add integration** + +You need a member role that can manage integrations, such as Admin. + + + + + +1. **Name**: enter a recognizable name, such as `Flashduty` +2. **URL**: paste the full push URL of the Flashduty integration +3. **Sign this webhook**: leave it unchecked. Flashduty authenticates the delivery by the `integration_key` in the push URL + + + + + +Without a policy, LaunchDarkly sends only flag changes in the **production** environment. To send other environments or segment changes, add this policy: + +```json +[ + { + "effect": "allow", + "actions": ["*"], + "resources": ["proj/*:env/*:flag/*", "proj/*:env/*:segment/*"] + } +] +``` + +Replace `env/*` with a specific environment (such as `env/production`) to send only that environment. Accept the terms and click **Save settings**. + + + + +LaunchDarkly has no test delivery button. After saving, make one change to any flag and the record appears in the Flashduty change list. + +## What one change is +--- + +| LaunchDarkly object | Change key (change_key) | Notes | +|---|---|---| +| Change history entry | The entry's `_id` | Every save of a flag or segment creates one entry, which becomes one Flashduty change; turning the same flag on and then off is two changes | + +## Status mapping +--- + +| LaunchDarkly entry | Flashduty change status | +|---|---| +| A flag or segment change (on/off, targeting rules, default rule, variations, create, delete, archive, applying an approval request, and so on) | Done | + +These deliveries are accepted without creating a change: + +- Entries for other resource kinds, such as projects, environments, members, roles, webhooks, metrics, and experiments +- Entries that contain only the following actions, which do not change how a flag evaluates: + - Creating, updating, reviewing, or deleting an approval request (once an approval request is applied, LaunchDarkly sends the entry for that step) + - Creating or updating scheduled changes (the entry for the scheduled change is sent when it runs) + - Name, description, tags, maintainer, temporary flag, deprecation, custom properties, rule descriptions, code references, flag links, followers, and segment exports + +## Change content +--- + +| Field | Content | +|---|---| +| Title | ` in : `, such as `Checkout redesign in production: turned on the flag`; project-wide actions (such as creating a flag) name no environment | +| Description | The change comment and LaunchDarkly's change details | +| Link | The flag or segment page in LaunchDarkly | + +Labels can be used in routes and to filter the change list: + +| Label | Description | +|---|---| +| `project` | Project key | +| `environment` | Environment key, such as `production`; absent for project-wide actions | +| `flag` | Flag key (flag changes) | +| `segment` | Segment key (segment changes) | +| `kind` | `flag` or `segment` | +| `action` | LaunchDarkly actions, comma-separated when there are several, such as `updateOn` or `updateRules` | +| `actor` | The name of the member who made the change, or the access token or application name for API changes | +| `audit_log_id` | Change history entry ID | + +## FAQ +--- + + + + +Without a policy, LaunchDarkly sends only flag changes in the production environment. Add a policy as described in **Choose what to send**. + + + + + +No. When a delivery fails, LaunchDarkly retries it once with the same content, and Flashduty records it once. + + + + + +LaunchDarkly does not guarantee chronological delivery. Flashduty uses the entry's own time (`date`) as the change time. + + + + + +- `_id is missing`: the payload is incomplete. Make sure the delivery comes from a native LaunchDarkly webhook +- `invalid date`: the time field in the payload is malformed + + + diff --git a/integration-docs/src/doc-map.mjs b/integration-docs/src/doc-map.mjs index e581768e1..7e5dfcc8c 100644 --- a/integration-docs/src/doc-map.mjs +++ b/integration-docs/src/doc-map.mjs @@ -101,6 +101,7 @@ export const docMap = { CustomChange: `${integrationBase}/change-integration/custom-event.mdx`, GithubChange: `${integrationBase}/change-integration/github.mdx`, + LaunchdarklyChange: `${integrationBase}/change-integration/launchdarkly.mdx`, Jira: { zh: 'legacy/zh/jira-change.md', en: 'legacy/en/jira-change.md', diff --git a/zh/on-call/integration/change-integration/launchdarkly.mdx b/zh/on-call/integration/change-integration/launchdarkly.mdx new file mode 100644 index 000000000..0e16b8903 --- /dev/null +++ b/zh/on-call/integration/change-integration/launchdarkly.mdx @@ -0,0 +1,139 @@ +--- +title: "LaunchDarkly 变更集成" +description: "通过 LaunchDarkly Webhook 将功能开关(Feature Flag)和用户分群(Segment)的变更同步到 Flashduty On-call,作为变更事件与告警、故障关联。" +keywords: ["变更集成", "LaunchDarkly", "Feature Flag", "功能开关", "Webhook"] +--- + +**版本要求**:此功能需要 On-call 标准版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/) + +通过 LaunchDarkly 组织级 Webhook,将功能开关(Flag)和用户分群(Segment)的变更同步到 Flashduty On-call。LaunchDarkly 的变更历史(Change history)中每一条 Flag 或 Segment 记录对应一条 Flashduty 变更,例如打开或关闭开关、修改定向规则、修改默认规则。 + +LaunchDarkly 推送的是已经生效的变更,因此每条变更都直接记录为 **Done**。 + +
+ +## 在 Flashduty On-call +--- + +1. 进入 Flashduty 控制台,选择 **集成中心 → 变更事件** +2. 选择 **LaunchDarkly**,填写集成名称 +3. 如需把变更分派到指定协作空间,在集成的 **路由** 中按标签(例如 `project`、`environment`、`flag`)配置规则 +4. 点击 **保存**,复制生成的 **推送地址** + +
+ +## 在 LaunchDarkly 中配置 +--- + + + + +1. 点击左侧栏的 **齿轮** 图标,进入 **Organization settings** +2. 点击 **Integrations**,找到 **Webhooks**,点击 **Add integration** + +需要能管理集成的成员角色(例如 Admin)。 + + + + + +1. **Name**:填写便于识别的名称,例如 `Flashduty` +2. **URL**:粘贴 Flashduty 集成的完整推送地址 +3. **Sign this webhook**:无需勾选,Flashduty 通过推送地址中的 `integration_key` 鉴权 + + + + + +不添加策略(Policy)时,LaunchDarkly 只推送 **production** 环境的 Flag 变更。如需推送其他环境或 Segment 变更,添加如下策略: + +```json +[ + { + "effect": "allow", + "actions": ["*"], + "resources": ["proj/*:env/*:flag/*", "proj/*:env/*:segment/*"] + } +] +``` + +将 `env/*` 替换为具体环境(例如 `env/production`)即可只推送该环境。勾选同意条款后点击 **Save settings**。 + + + + +LaunchDarkly 没有测试推送按钮。保存后在任一 Flag 上做一次变更,即可在 Flashduty 变更列表中看到记录。 + +## 一条变更是什么 +--- + +| LaunchDarkly 对象 | 变更标识(change_key) | 说明 | +|---|---|---| +| 变更历史记录(Change history entry) | 记录的 `_id` | 每次保存 Flag 或 Segment 产生一条记录,对应一条 Flashduty 变更;同一个开关先打开再关闭是两条变更 | + +## 状态映射 +--- + +| LaunchDarkly 记录 | Flashduty 变更状态 | +|---|---| +| Flag 或 Segment 的变更(开关、定向规则、默认规则、变体、创建、删除、归档、应用审批请求等) | Done | + +以下推送返回成功但不生成变更: + +- 其他资源类型的记录,例如项目、环境、成员、角色、Webhook、指标、实验 +- 只包含以下动作的记录,它们不改变 Flag 的求值结果: + - 审批请求的创建、修改、评审、删除(审批通过并应用后,LaunchDarkly 会推送应用这一步的记录) + - 定时变更的创建和修改(到期执行时会推送执行的记录) + - 名称、描述、标签、维护者、临时标记、弃用标记、自定义属性、规则描述、代码引用、Flag 链接、关注者、Segment 导出 + +## 变更内容 +--- + +| 字段 | 内容 | +|---|---| +| 标题 | ` in <环境>: <动作描述>`,例如 `Checkout redesign in production: turned on the flag`;项目级动作(例如创建 Flag)不带环境 | +| 描述 | 变更备注(Comment)与 LaunchDarkly 的变更明细 | +| 链接 | LaunchDarkly 中该 Flag 或 Segment 的页面 | + +标签可用于路由和在变更列表中筛选: + +| 标签 | 说明 | +|---|---| +| `project` | 项目 key | +| `environment` | 环境 key,例如 `production`;项目级动作没有此标签 | +| `flag` | Flag key(Flag 变更) | +| `segment` | Segment key(Segment 变更) | +| `kind` | `flag` 或 `segment` | +| `action` | LaunchDarkly 动作,多个时以逗号分隔,例如 `updateOn`、`updateRules` | +| `actor` | 操作的成员姓名,通过 API 操作时为 Access token 或应用名称 | +| `audit_log_id` | 变更历史记录 ID | + +## 常见问题 +--- + + + + +未配置策略时 LaunchDarkly 只推送 production 环境的 Flag 变更。按上文 **选择推送范围** 添加策略。 + + + + + +不会。推送失败时 LaunchDarkly 会重试一次,重试内容与原推送相同,Flashduty 只记录一次。 + + + + + +LaunchDarkly 不保证按时间顺序推送。Flashduty 使用记录自身的时间(`date`)作为变更时间。 + + + + + +- `_id is missing`:推送内容不完整,请确认推送来自 LaunchDarkly 原生 Webhook +- `invalid date`:推送中的时间字段格式不正确 + + + From ae669f55c3830b51483e06afcd7d4051d259f131 Mon Sep 17 00:00:00 2001 From: ysyneu Date: Mon, 28 Sep 2026 09:50:01 -0700 Subject: [PATCH 08/36] docs(change): add Netlify change integration page --- docs.json | 6 +- .../change-integration/netlify.mdx | 130 ++++++++++++++++++ integration-docs/src/doc-map.mjs | 1 + .../change-integration/netlify.mdx | 130 ++++++++++++++++++ 4 files changed, 265 insertions(+), 2 deletions(-) create mode 100644 en/on-call/integration/change-integration/netlify.mdx create mode 100644 zh/on-call/integration/change-integration/netlify.mdx diff --git a/docs.json b/docs.json index 37d503c6c..1cee74d3a 100644 --- a/docs.json +++ b/docs.json @@ -1775,7 +1775,8 @@ "group": "变更集成", "pages": [ "zh/on-call/integration/change-integration/custom-event", - "zh/on-call/integration/change-integration/github" + "zh/on-call/integration/change-integration/github", + "zh/on-call/integration/change-integration/netlify" ] }, { @@ -3174,7 +3175,8 @@ "group": "Change Integration", "pages": [ "en/on-call/integration/change-integration/custom-event", - "en/on-call/integration/change-integration/github" + "en/on-call/integration/change-integration/github", + "en/on-call/integration/change-integration/netlify" ] }, { diff --git a/en/on-call/integration/change-integration/netlify.mdx b/en/on-call/integration/change-integration/netlify.mdx new file mode 100644 index 000000000..0cd347050 --- /dev/null +++ b/en/on-call/integration/change-integration/netlify.mdx @@ -0,0 +1,130 @@ +--- +title: "Netlify change integration" +description: "Sync Netlify deploys to Flashduty On-call through Netlify deploy notifications (HTTP POST request), as change events you can correlate with alerts and incidents." +keywords: ["change integration", "Netlify", "deploy notifications", "Deploy notifications", "Webhook", "deployment events"] +--- + +**Plan requirement**: This feature requires an On-call Standard or higher subscription. [Learn more](https://flashcat.cloud/flashduty/price/) + +Use a Netlify project's deploy notifications to sync deploys to Flashduty On-call. Each deploy becomes one Flashduty change; every notification of that deploy, from waiting for approval and building to success or failure, updates that same change. + +Production deploys, branch deploys, and Deploy Previews are all sent; the `environment` label tells them apart. HTTP POST request deploy notifications are available on every Netlify plan. + +
+ +## In Flashduty On-call +--- + +1. In the Flashduty console, go to **Integration Center → Change Events** +2. Select **Netlify** and enter an integration name +3. To assign changes to specific channels, add rules under the integration's **Routes** that match labels such as `project` or `environment` +4. Click **Save** and copy the generated **Push URL** + +
+ +## Configure Netlify +--- + +Each Netlify notification listens to one event, so add one notification for each event in the table below, all with the same Push URL. + + + + +In your Netlify project, go to **Project configuration → Notifications → Deploy notifications**, click **Add notification**, and select **HTTP POST request**. + + + + + +1. **Event to listen for**: select one event, see the next step +2. **URL to notify**: paste the complete Flashduty integration Push URL +3. **JWS secret token**: leave it empty; Flashduty authenticates the request by the `integration_key` in the Push URL +4. Click **Save** + + + + + +| Event | Needed | +|---|---| +| Deploy started | Required | +| Deploy succeeded | Required | +| Deploy failed | Required | +| Deploy restored | Recommended, records rollbacks | +| Deploy request pending, Deploy request accepted, Deploy request rejected | Add these when the project requires approval for untrusted deploys | + +Deploy locked, Deploy unlocked, and Deploy deleted are not needed: they do not change a deploy's result, and Flashduty accepts them without creating a change. Previously successful deploy failed and Previously failed deploy succeeded repeat Deploy failed and Deploy succeeded, so they are not needed either. + + + + +## What one change is +--- + +| Netlify object | Change key (change_key) | Notes | +|---|---|---| +| Deploy | The deploy ID (`id`) | Every notification of one deploy updates the same change; two deploys of the same project and branch are two changes | + +A rollback (Deploy restored) publishes an existing deploy again, so it updates that deploy's change with status Done and the rollback time as the event time. + +## Status mapping +--- + +| Netlify event | Flashduty change status | +|---|---| +| Deploy request pending | Planned | +| Deploy request accepted | Ready | +| Deploy started | Processing | +| Deploy succeeded | Done | +| Deploy restored | Done | +| Deploy failed | Failed | +| Deploy request rejected | Canceled | + +Done, Failed, and Canceled are end states; Flashduty records the change's end time when one arrives. + +## Change content +--- + +| Field | Content | +|---|---| +| Title | `: deploy () to `, such as `example-site: deploy main (f95f852) to production`; a manual deploy without a branch or commit gives `: deploy to ` | +| Description | The deploy's title, usually the commit message or the message entered for a manual deploy | +| Link | The deploy's page in the Netlify console | + +Labels can be used in routes and to filter the change list: + +| Label | Description | +|---|---| +| `project` | Netlify project name | +| `site_id` | Netlify project ID | +| `environment` | Deploy context: `production`, `deploy-preview`, `branch-deploy`, and so on | +| `ref` | The branch deployed | +| `sha` | Full commit SHA deployed | +| `deploy_id` | Netlify deploy ID | +| `review_id` | The pull request number of a Deploy Preview | +| `state` | The Netlify deploy state in the latest notification, such as `building`, `ready`, or `error` | +| `error_message` | Netlify's error message when a deploy fails | + +## FAQ +--- + + + + +Each Netlify notification sends one event. Make sure Deploy started, Deploy succeeded, and Deploy failed each have their own notification. + + + + + +No. A notification with the same deploy, state, and time is recorded once. + + + + + +- `unsupported X-Netlify-Event`: Flashduty received a Netlify event it does not support yet. Contact us +- `deploy id is missing`: the payload is incomplete. Make sure the delivery comes from a Netlify deploy notification + + + diff --git a/integration-docs/src/doc-map.mjs b/integration-docs/src/doc-map.mjs index e581768e1..08860128d 100644 --- a/integration-docs/src/doc-map.mjs +++ b/integration-docs/src/doc-map.mjs @@ -101,6 +101,7 @@ export const docMap = { CustomChange: `${integrationBase}/change-integration/custom-event.mdx`, GithubChange: `${integrationBase}/change-integration/github.mdx`, + NetlifyChange: `${integrationBase}/change-integration/netlify.mdx`, Jira: { zh: 'legacy/zh/jira-change.md', en: 'legacy/en/jira-change.md', diff --git a/zh/on-call/integration/change-integration/netlify.mdx b/zh/on-call/integration/change-integration/netlify.mdx new file mode 100644 index 000000000..091ce101f --- /dev/null +++ b/zh/on-call/integration/change-integration/netlify.mdx @@ -0,0 +1,130 @@ +--- +title: "Netlify 变更集成" +description: "通过 Netlify 部署通知(HTTP POST request)将部署同步到 Flashduty On-call,作为变更事件与告警、故障关联。" +keywords: ["变更集成", "Netlify", "部署通知", "Deploy notifications", "Webhook", "部署事件"] +--- + +**版本要求**:此功能需要 On-call 标准版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/) + +通过 Netlify 项目的部署通知(Deploy notifications),将部署同步到 Flashduty On-call。每一次部署(Deploy)对应一条 Flashduty 变更;部署从等待审批、开始构建到成功或失败的每个通知,都会更新同一条变更。 + +生产部署、分支部署和 Deploy Preview 都会推送,可以用 `environment` 标签区分。Netlify 所有套餐都支持 HTTP POST request 类型的部署通知。 + +
+ +## 在 Flashduty On-call +--- + +1. 进入 Flashduty 控制台,选择 **集成中心 → 变更事件** +2. 选择 **Netlify**,填写集成名称 +3. 如需把变更分派到指定协作空间,在集成的 **路由** 中按标签(例如 `project`、`environment`)配置规则 +4. 点击 **保存**,复制生成的 **推送地址** + +
+ +## 在 Netlify 中配置 +--- + +Netlify 的每条通知只监听一个事件,需要为下表中的每个事件各添加一条通知,推送地址相同。 + + + + +进入 Netlify 项目,选择 **Project configuration → Notifications → Deploy notifications**,点击 **Add notification**,选择 **HTTP POST request**。 + + + + + +1. **Event to listen for**:选择一个事件,见下一步 +2. **URL to notify**:粘贴 Flashduty 集成的完整推送地址 +3. **JWS secret token**:留空即可,Flashduty 通过推送地址中的 `integration_key` 鉴权 +4. 点击 **Save** + + + + + +| 事件 | 是否需要 | +|---|---| +| Deploy started | 必需 | +| Deploy succeeded | 必需 | +| Deploy failed | 必需 | +| Deploy restored | 建议,记录回滚 | +| Deploy request pending、Deploy request accepted、Deploy request rejected | 项目开启了部署审批(不受信任的部署需要批准)时添加 | + +无需添加 Deploy locked、Deploy unlocked、Deploy deleted:它们不改变部署结果,Flashduty 返回成功但不生成变更。Previously successful deploy failed 和 Previously failed deploy succeeded 与 Deploy failed、Deploy succeeded 重复,也无需添加。 + + + + +## 一条变更是什么 +--- + +| Netlify 对象 | 变更标识(change_key) | 说明 | +|---|---|---| +| Deploy | 部署 ID(`id`) | 同一次部署的所有通知更新同一条变更;同一项目、同一分支的两次部署是两条变更 | + +回滚(Deploy restored)重新发布的是一次已有的部署,因此会更新那次部署对应的变更,状态为 Done,事件时间为回滚时间。 + +## 状态映射 +--- + +| Netlify 事件 | Flashduty 变更状态 | +|---|---| +| Deploy request pending | Planned | +| Deploy request accepted | Ready | +| Deploy started | Processing | +| Deploy succeeded | Done | +| Deploy restored | Done | +| Deploy failed | Failed | +| Deploy request rejected | Canceled | + +Done、Failed 和 Canceled 是结束状态,Flashduty 会记录变更结束时间。 + +## 变更内容 +--- + +| 字段 | 内容 | +|---|---| +| 标题 | `<项目名>: deploy <分支> (<短 SHA>) to <部署上下文>`,例如 `example-site: deploy main (f95f852) to production`;手动部署没有分支和提交时为 `<项目名>: deploy to <部署上下文>` | +| 描述 | 部署的 title,通常是提交信息或手动部署时填写的说明 | +| 链接 | Netlify 控制台中这次部署的页面 | + +标签可用于路由和在变更列表中筛选: + +| 标签 | 说明 | +|---|---| +| `project` | Netlify 项目名 | +| `site_id` | Netlify 项目 ID | +| `environment` | 部署上下文:`production`、`deploy-preview`、`branch-deploy` 等 | +| `ref` | 部署的分支 | +| `sha` | 部署的完整提交 SHA | +| `deploy_id` | Netlify 部署 ID | +| `review_id` | Deploy Preview 对应的 Pull Request 编号 | +| `state` | 最新通知中的 Netlify 部署状态,例如 `building`、`ready`、`error` | +| `error_message` | 部署失败时 Netlify 给出的错误信息 | + +## 常见问题 +--- + + + + +Netlify 的每条通知只推送一个事件。请确认 Deploy started、Deploy succeeded、Deploy failed 三个事件都已各自添加了一条通知。 + + + + + +不会。同一部署、同一状态、同一时间的通知只记录一次。 + + + + + +- `unsupported X-Netlify-Event`:收到了 Flashduty 尚未支持的 Netlify 事件,请联系我们 +- `deploy id is missing`:推送内容不完整,请确认推送来自 Netlify 部署通知 + + + From 659aa41936313a8a6f8bae27afdbb6f397a32a0c Mon Sep 17 00:00:00 2001 From: ysyneu Date: Mon, 28 Sep 2026 09:53:33 -0700 Subject: [PATCH 09/36] docs: add HCP Terraform change integration page --- docs.json | 6 +- .../change-integration/hcp-terraform.mdx | 133 ++++++++++++++++++ integration-docs/src/doc-map.mjs | 1 + .../change-integration/hcp-terraform.mdx | 133 ++++++++++++++++++ 4 files changed, 271 insertions(+), 2 deletions(-) create mode 100644 en/on-call/integration/change-integration/hcp-terraform.mdx create mode 100644 zh/on-call/integration/change-integration/hcp-terraform.mdx diff --git a/docs.json b/docs.json index 37d503c6c..3382d9599 100644 --- a/docs.json +++ b/docs.json @@ -1775,7 +1775,8 @@ "group": "变更集成", "pages": [ "zh/on-call/integration/change-integration/custom-event", - "zh/on-call/integration/change-integration/github" + "zh/on-call/integration/change-integration/github", + "zh/on-call/integration/change-integration/hcp-terraform" ] }, { @@ -3174,7 +3175,8 @@ "group": "Change Integration", "pages": [ "en/on-call/integration/change-integration/custom-event", - "en/on-call/integration/change-integration/github" + "en/on-call/integration/change-integration/github", + "en/on-call/integration/change-integration/hcp-terraform" ] }, { diff --git a/en/on-call/integration/change-integration/hcp-terraform.mdx b/en/on-call/integration/change-integration/hcp-terraform.mdx new file mode 100644 index 000000000..6fa044a5c --- /dev/null +++ b/en/on-call/integration/change-integration/hcp-terraform.mdx @@ -0,0 +1,133 @@ +--- +title: "HCP Terraform change integration" +description: "Sync Terraform runs to Flashduty On-call through HCP Terraform workspace notifications, as change events you can correlate with alerts and incidents." +keywords: ["change integration", "HCP Terraform", "Terraform Cloud", "Run", "Webhook", "infrastructure changes"] +--- + +**Plan requirement**: This feature requires an On-call Standard or higher subscription. [Learn more](https://flashcat.cloud/flashduty/price/) + +Use HCP Terraform (formerly Terraform Cloud) workspace notifications to sync Terraform runs to Flashduty On-call. Each run becomes one Flashduty change; every state of a run, from created through planning, waiting for confirmation, and applying to completed, errored, or canceled, updates that same change. + +
+ +## In Flashduty On-call +--- + +1. In the Flashduty console, go to **Integration Center → Change Events** +2. Select **HCP Terraform** and enter an integration name +3. To assign changes to specific channels, add rules under the integration's **Routes** that match labels such as `organization` or `workspace` +4. Click **Save** and copy the generated **Push URL** + +
+ +## Configure HCP Terraform +--- + +Notifications are configured per workspace, so configure one for each workspace you want to connect. You need admin permission on the workspace. + + + + +In the workspace, go to **Settings → Notifications** and click **Create a Notification**. + + + + + +1. **Destination**: select **Webhook** +2. **Name**: enter a recognizable name, such as `Flashduty` +3. **Webhook URL**: paste the complete Flashduty integration Push URL +4. **Token**: leave it empty; Flashduty authenticates with the `integration_key` in the Push URL + + + + + +1. Under **Run Events**, choose to send only specific events and check **Created**, **Planning**, **Needs Attention**, **Applying**, **Completed**, and **Errored** +2. Leave **Workspace Events** (drift detection, auto destroy, and so on) unselected; Flashduty ignores these notifications +3. Click **Create a notification** + +When you save, HCP Terraform sends a verification request. Flashduty accepts it without creating a change. You can verify again later with **Send a Test**. + + + + +You can also manage this configuration with the Terraform `tfe` provider: a `tfe_notification_configuration` resource with `destination_type = "generic"`, `url` set to the Push URL, and `triggers` set to `["run:created", "run:planning", "run:needs_attention", "run:applying", "run:completed", "run:errored"]`. + +## What one change is +--- + +| HCP Terraform object | Change key (change_key) | Notes | +|---|---|---| +| Run | `run_id`, for example `run-FwnENkvDnrpyFC7M` | Every notification of one run updates the same change; two runs of the same workspace are two changes | + +## Status mapping +--- + +| Notification trigger | Run status (run_status) | Flashduty change status | +|---|---|---| +| run:created | pending | Ready | +| run:planning | planning | Processing | +| run:needs_attention | for example planned or policy_override (waiting for confirmation) | Planned | +| run:applying | applying | Processing | +| run:completed | applied, planned_and_finished | Done | +| run:errored | errored, policy_soft_failed | Failed | +| run:errored | canceled, force_canceled, discarded | Canceled | + +Done, Failed, and Canceled are end states; Flashduty records the change's end time. + +`planned_and_finished` means a run that only planned (no changes, or a plan-only run). It is also recorded as Done; use the `run_status` label to tell it apart. + +The following deliveries are accepted without creating a change: the verification request sent on save or by **Send a Test** (trigger `verification`), health assessment notifications (`assessment:drifted`, `assessment:check_failure`, `assessment:failed`), and workspace notifications (`workspace:auto_destroy_reminder`, `workspace:auto_destroy_run_results`, `workspace:deleted`). + +## Change content +--- + +| Field | Content | +|---|---| +| Title | `/: terraform run ` | +| Description | The run message (why the run was queued, such as a VCS commit message or a message entered manually) | +| Link | The run's page in HCP Terraform | + +Use labels for routing and for filtering the change list: + +| Label | Description | +|---|---| +| `organization` | HCP Terraform organization name | +| `workspace` | Workspace name | +| `workspace_id` | Workspace ID, for example `ws-XdeUVMWShTesDMME` | +| `run_id` | Run ID | +| `run_status` | Run status in the latest notification | +| `actor` | User who created the run | + +## FAQ +--- + + + + +- Make sure the notification is enabled and **Run Events** are selected. **Workspace Events** alone create no changes +- Check recent deliveries and Flashduty's responses on the notification configuration page +- Notifications are per workspace; make sure the run's workspace has this notification configured + + + + + +No. An event with the same run, status, and time is recorded only once. + + + + + +No. A health assessment reports resources drifting from their configuration, not a change. Flashduty accepts it and ignores it. + + + + + +- `unsupported notifications[].trigger` or `unsupported notifications[].run_status`: Flashduty received a trigger or run status it does not support yet; contact us +- `run_id is missing`: the payload is incomplete; make sure it comes from an HCP Terraform webhook notification + + + diff --git a/integration-docs/src/doc-map.mjs b/integration-docs/src/doc-map.mjs index e581768e1..8634cdbf7 100644 --- a/integration-docs/src/doc-map.mjs +++ b/integration-docs/src/doc-map.mjs @@ -101,6 +101,7 @@ export const docMap = { CustomChange: `${integrationBase}/change-integration/custom-event.mdx`, GithubChange: `${integrationBase}/change-integration/github.mdx`, + HcpTerraformChange: `${integrationBase}/change-integration/hcp-terraform.mdx`, Jira: { zh: 'legacy/zh/jira-change.md', en: 'legacy/en/jira-change.md', diff --git a/zh/on-call/integration/change-integration/hcp-terraform.mdx b/zh/on-call/integration/change-integration/hcp-terraform.mdx new file mode 100644 index 000000000..1cc44b17b --- /dev/null +++ b/zh/on-call/integration/change-integration/hcp-terraform.mdx @@ -0,0 +1,133 @@ +--- +title: "HCP Terraform 变更集成" +description: "通过 HCP Terraform 工作区通知将 Terraform Run 同步到 Flashduty On-call,作为变更事件与告警、故障关联。" +keywords: ["变更集成", "HCP Terraform", "Terraform Cloud", "Run", "Webhook", "基础设施变更"] +--- + +**版本要求**:此功能需要 On-call 标准版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/) + +通过 HCP Terraform(原 Terraform Cloud)工作区的通知配置(Notification),将 Terraform Run 同步到 Flashduty On-call。每一次 Run 对应一条 Flashduty 变更;Run 从创建、Plan、等待确认、Apply 到完成、出错或取消的每个状态,都会更新同一条变更。 + +
+ +## 在 Flashduty On-call +--- + +1. 进入 Flashduty 控制台,选择 **集成中心 → 变更事件** +2. 选择 **HCP Terraform**,填写集成名称 +3. 如需把变更分派到指定协作空间,在集成的 **路由** 中按标签(例如 `organization`、`workspace`)配置规则 +4. 点击 **保存**,复制生成的 **推送地址** + +
+ +## 在 HCP Terraform 中配置 +--- + +通知按工作区配置,每个需要接入的工作区配置一次。需要该工作区的管理员权限。 + + + + +进入工作区,选择 **Settings → Notifications**,点击 **Create a Notification**。 + + + + + +1. **Destination**:选择 **Webhook** +2. **Name**:填写便于识别的名称,例如 `Flashduty` +3. **Webhook URL**:粘贴 Flashduty 集成的完整推送地址 +4. **Token**:留空即可,Flashduty 通过推送地址中的 `integration_key` 鉴权 + + + + + +1. 在 **Run Events** 中选择只发送特定事件,勾选 **Created**、**Planning**、**Needs Attention**、**Applying**、**Completed** 和 **Errored** +2. **Workspace Events**(漂移检测、自动销毁等)无需勾选,Flashduty 会忽略这类通知 +3. 点击 **Create a notification** + +保存时 HCP Terraform 会发送一次验证请求,Flashduty 返回成功但不会生成变更。之后可以用 **Send a Test** 再次验证。 + + + + +也可以使用 Terraform 的 `tfe` Provider 管理这项配置:`tfe_notification_configuration` 资源设置 `destination_type = "generic"`、`url` 为推送地址、`triggers` 为 `["run:created", "run:planning", "run:needs_attention", "run:applying", "run:completed", "run:errored"]`。 + +## 一条变更是什么 +--- + +| HCP Terraform 对象 | 变更标识(change_key) | 说明 | +|---|---|---| +| Run | `run_id`,例如 `run-FwnENkvDnrpyFC7M` | 同一个 Run 的所有通知更新同一条变更;同一工作区的两次 Run 是两条变更 | + +## 状态映射 +--- + +| 通知触发事件(trigger) | Run 状态(run_status) | Flashduty 变更状态 | +|---|---|---| +| run:created | pending | Ready | +| run:planning | planning | Processing | +| run:needs_attention | 例如 planned、policy_override(等待人工确认) | Planned | +| run:applying | applying | Processing | +| run:completed | applied、planned_and_finished | Done | +| run:errored | errored、policy_soft_failed | Failed | +| run:errored | canceled、force_canceled、discarded | Canceled | + +Done、Failed 和 Canceled 是结束状态,Flashduty 会记录变更结束时间。 + +`planned_and_finished` 表示只做了 Plan 的 Run(无变更或 Plan-only),同样记为 Done,可以通过 `run_status` 标签区分。 + +以下推送返回成功但不生成变更:保存配置或 **Send a Test** 时的验证请求(trigger 为 `verification`)、健康评估通知(`assessment:drifted`、`assessment:check_failure`、`assessment:failed`)和工作区通知(`workspace:auto_destroy_reminder`、`workspace:auto_destroy_run_results`、`workspace:deleted`)。 + +## 变更内容 +--- + +| 字段 | 内容 | +|---|---| +| 标题 | `<组织>/<工作区>: terraform run ` | +| 描述 | Run 的 message(触发原因,例如 VCS 提交信息或手动填写的说明) | +| 链接 | HCP Terraform 中该 Run 的页面 | + +标签可用于路由和在变更列表中筛选: + +| 标签 | 说明 | +|---|---| +| `organization` | HCP Terraform 组织名称 | +| `workspace` | 工作区名称 | +| `workspace_id` | 工作区 ID,例如 `ws-XdeUVMWShTesDMME` | +| `run_id` | Run ID | +| `run_status` | 最新通知中的 Run 状态 | +| `actor` | 创建 Run 的用户 | + +## 常见问题 +--- + + + + +- 确认通知配置已启用,且勾选了 **Run Events**。只勾选 **Workspace Events** 时不会产生变更 +- 在通知配置页面查看最近的推送记录和 Flashduty 的响应 +- 通知按工作区配置,确认 Run 所在的工作区配置了该通知 + + + + + +不会。同一 Run、同一状态、同一时间的事件只记录一次。 + + + + + +不会。健康评估反映的是资源状态偏离配置,不是一次变更,Flashduty 收到后返回成功并忽略。 + + + + + +- `unsupported notifications[].trigger` 或 `unsupported notifications[].run_status`:收到了 Flashduty 尚未支持的触发事件或 Run 状态,请联系我们 +- `run_id is missing`:推送内容不完整,请确认推送来自 HCP Terraform 的 Webhook 通知 + + + From a5dda62097f79fff1869ba07ab025fa007b1e4c5 Mon Sep 17 00:00:00 2001 From: ysyneu Date: Mon, 28 Sep 2026 09:55:27 -0700 Subject: [PATCH 10/36] docs(change): add Argo CD change integration Argo CD Notifications webhook service, template and trigger that record each Application sync operation as a Flashduty change, with the phase-to-status mapping, the change key and the label reference. --- docs.json | 6 +- .../integration/change-integration/argocd.mdx | 220 ++++++++++++++++++ integration-docs/src/doc-map.mjs | 1 + .../integration/change-integration/argocd.mdx | 220 ++++++++++++++++++ 4 files changed, 445 insertions(+), 2 deletions(-) create mode 100644 en/on-call/integration/change-integration/argocd.mdx create mode 100644 zh/on-call/integration/change-integration/argocd.mdx diff --git a/docs.json b/docs.json index 37d503c6c..b6ff0bcf6 100644 --- a/docs.json +++ b/docs.json @@ -1775,7 +1775,8 @@ "group": "变更集成", "pages": [ "zh/on-call/integration/change-integration/custom-event", - "zh/on-call/integration/change-integration/github" + "zh/on-call/integration/change-integration/github", + "zh/on-call/integration/change-integration/argocd" ] }, { @@ -3174,7 +3175,8 @@ "group": "Change Integration", "pages": [ "en/on-call/integration/change-integration/custom-event", - "en/on-call/integration/change-integration/github" + "en/on-call/integration/change-integration/github", + "en/on-call/integration/change-integration/argocd" ] }, { diff --git a/en/on-call/integration/change-integration/argocd.mdx b/en/on-call/integration/change-integration/argocd.mdx new file mode 100644 index 000000000..6deee3fed --- /dev/null +++ b/en/on-call/integration/change-integration/argocd.mdx @@ -0,0 +1,220 @@ +--- +title: "Argo CD change integration" +description: "Sync Argo CD application sync operations to Flashduty On-call through an Argo CD Notifications webhook service, as change events you can correlate with alerts and incidents." +keywords: ["change integration", "Argo CD", "ArgoCD", "GitOps", "Sync", "Notifications", "Webhook", "deployment events"] +--- + +**Plan requirement**: This feature requires an On-call Standard or higher subscription. [Learn more](https://flashcat.cloud/flashduty/price/) + +Argo CD pushes changes through its built-in **Notifications** (`argocd-notifications-controller`). This integration provides an `argocd-notifications-cm` configuration with one webhook service, one request body template, and one trigger. Each sync operation of an Argo CD Application becomes one Flashduty change: it is recorded as Processing when the sync starts and updated to Done, Failed, or Canceled when it ends. + +Automated syncs, manual syncs from the UI or CLI, and rollbacks are all sync operations and are all recorded. For sync-failed and health-degraded alerts, use the Argo CD alert integration; both integrations can be configured side by side. + +
+ +## In Flashduty On-call +--- + +1. In the Flashduty console, go to **Integration Center → Change Events** +2. Select **Argo CD** and enter an integration name +3. To assign changes to specific channels, add rules under the integration's **Routes** that match labels such as `application`, `project`, or `destination_namespace` +4. Click **Save** and copy the generated **Push URL** + +
+ +## Configure Argo CD +--- + +The steps below need Kubernetes permission to edit ConfigMaps in the Argo CD namespace (`argocd` by default) and to edit annotations on Applications or AppProjects. The Argo CD cluster must be able to reach the domain of the push URL. + + + + +Save the following as `flashduty-change.yaml` and replace `url` with the push URL copied above (including `?integration_key=...`): + +```yaml +data: + service.webhook.flashduty-change: | + url: + headers: + - name: Content-Type + value: application/json + + template.flashduty-change: | + webhook: + flashduty-change: + method: POST + body: | + { + "app_uid": {{ .app.metadata.uid | toJson }}, + "app_name": {{ .app.metadata.name | toJson }}, + "app_namespace": {{ .app.metadata.namespace | toJson }}, + "project": {{ .app.spec.project | toJson }}, + "destination": {{ dig "spec" "destination" "name" (dig "spec" "destination" "server" "" .app) .app | toJson }}, + "destination_namespace": {{ dig "spec" "destination" "namespace" "" .app | toJson }}, + "argocd_url": {{ .context.argocdUrl | toJson }}, + "phase": {{ dig "status" "operationState" "phase" "" .app | toJson }}, + "message": {{ dig "status" "operationState" "message" "" .app | toJson }}, + "started_at": {{ dig "status" "operationState" "startedAt" "" .app | toJson }}, + "finished_at": {{ dig "status" "operationState" "finishedAt" "" .app | toJson }}, + "revision": {{ dig "status" "operationState" "syncResult" "revision" (dig "status" "operationState" "operation" "sync" "revision" "" .app) .app | toJson }}, + "initiated_by": {{ dig "status" "operationState" "operation" "initiatedBy" "username" "" .app | toJson }}, + "automated": {{ dig "status" "operationState" "operation" "initiatedBy" "automated" false .app | toJson }}, + "dry_run": {{ dig "status" "operationState" "operation" "sync" "dryRun" false .app | toJson }} + } + + trigger.on-flashduty-change: | + - when: app.status.operationState != nil and app.status.operationState.phase in ['Running'] + oncePer: app.status.operationState?.startedAt + send: [flashduty-change] + - when: app.status.operationState != nil and app.status.operationState.phase in ['Succeeded', 'Failed', 'Error'] + oncePer: app.status.operationState?.startedAt + send: [flashduty-change] +``` + +Merge it into the existing `argocd-notifications-cm` (`--type merge` only adds or updates the keys above and leaves the rest of the configuration alone): + +```bash +kubectl patch configmap argocd-notifications-cm -n argocd --type merge --patch-file flashduty-change.yaml +``` + +If Argo CD is installed with the Helm chart, put `service.webhook.flashduty-change` under `notifications.notifiers`, the template under `notifications.templates`, and the trigger under `notifications.triggers`; otherwise the next upgrade overwrites manual edits. + +Notes: + +- Every value in the template is escaped with `toJson`, so quotes and line breaks in sync messages cannot break the JSON. Do not remove it. Do not rename fields; `app_uid`, `phase`, and `started_at` are required +- Optional fields are read with `dig`, so the template renders even when the application has never synced or the sync has no result yet +- The two trigger conditions cover the start and the end of a sync. `oncePer` is the sync operation's start time, so the start and the end of every sync operation are each sent once, even when Argo CD does not observe the state between two consecutive syncs. Do not remove it +- The service name `flashduty-change` differs from `flashduty` used by the alert integration, so the two integrations' push URLs do not interfere +- `argocd_url` comes from `context.argocdUrl` in `argocd-notifications-cm` and is used to build the change link. Without it, changes have no link but are still recorded + + + + + +A trigger sends only after it is subscribed. Choose one scope: + +- **One application**: add an annotation to the Application + + ```bash + kubectl patch application -n argocd --type merge \ + -p '{"metadata":{"annotations":{"notifications.argoproj.io/subscribe.on-flashduty-change.flashduty-change":""}}}' + ``` + +- **All applications in a project**: add the same annotation `notifications.argoproj.io/subscribe.on-flashduty-change.flashduty-change: ""` to the AppProject's `metadata.annotations` +- **All applications**: add an entry to `subscriptions` in `argocd-notifications-cm`. If `subscriptions` already exists (for example the entry added by the alert integration), append to the existing list instead of overwriting it with the merge command above + + ```yaml + subscriptions: | + - recipients: + - flashduty-change + triggers: + - on-flashduty-change + ``` + +When the subscription takes effect, each application that has synced before immediately sends the result of its latest sync, and Flashduty records it as one change with that sync's original start and end times. + + + + + +Argo CD has no button for sending a test message. From the `argocd-notifications-controller` Pod, use `argocd admin notifications template notify` to send one notification based on the application's current state: + +```bash +kubectl exec -n argocd deploy/argocd-notifications-controller -- \ + /usr/local/bin/argocd admin notifications template notify flashduty-change --recipient flashduty-change +``` + +If the command prints no error, Flashduty accepted the request. For an application that has synced before, this notification is the result of its latest sync and merges into that sync's existing record without adding a change; for an application that has never synced, Flashduty ignores it. + + + + + +Sync a subscribed application (click **Sync** in the UI, or run `argocd app sync `). Confirm that a Processing change appears in the Flashduty change list and is updated to Done or Failed when the sync ends. + + + + +## What one change is +--- + +One change is one sync operation of one application. Its change key (change_key) is `/`: + +- `app_uid` is the application's `metadata.uid`. Kubernetes assigns every object a UID that is unique over the whole lifetime of the cluster, so same-named applications in different Argo CD instances, and an application deleted and recreated, are different applications +- `started_at` is the sync operation's start time (`status.operationState.startedAt`, recorded in UTC). Argo CD writes it when the sync starts and keeps it through retries, and an application runs only one sync operation at a time + +So the start, the failed retries, and the final result of one sync update the same change, and two syncs of the same application are two changes, even when they sync the same revision. Changes to the application name, project, revision, or sync message do not change the change key. + +Flashduty rejects a request that lacks `app_uid` or `started_at`, or whose times are not in RFC 3339 format. + +## Status mapping +--- + +| Argo CD sync phase (`phase`) | Flashduty change status | +|---|---| +| `Running`, `Terminating` | Processing | +| `Succeeded` | Done | +| `Failed`, `Error` | Failed | +| `Failed` with the message `Operation terminated` (**Terminate** in the UI, or `argocd app terminate-op`) | Canceled | + +Done, Failed, and Canceled are end states; Flashduty records the change's end time. An operation that Argo CD terminates because of the sync timeout (the message contains `triggered by controller sync timeout`) is recorded as Failed. + +Sync phases are case-sensitive, and other values are rejected. The following deliveries return success without creating a change: an application with no sync operation yet (empty `phase`), and dry-run syncs. + +The recorded time is `started_at` when a sync starts and `finished_at` when it ends. While Argo CD retries a failed sync automatically, the phase stays `Running`, so the change is not marked Failed early. + +## Change content +--- + +- **Title**: `: sync to `. A Git commit shows its first 7 characters; other values, such as a Helm chart version, are shown as is. The revision or destination namespace part is omitted when empty +- **Link**: `/applications/`, only when `context.argocdUrl` is configured + +Labels can be used for routing and for filtering the change list: + +| Label | Description | +|---|---| +| `application` | Application name | +| `app_uid` | The application's `metadata.uid` | +| `app_namespace` | Namespace of the Application object | +| `project` | Argo CD project of the application | +| `destination` | Destination cluster name, or the cluster address when no name is set | +| `destination_namespace` | Destination namespace | +| `revision` | Synced revision (Git commit or chart version) | +| `actor` | User who started the sync; `automated` for automated syncs | +| `phase` | Latest sync phase | +| `message` | Latest sync message, such as the failure reason, truncated beyond 1024 bytes | + +Empty fields are not written as labels. + +## FAQ +--- + + + + +- Check the `argocd-notifications-controller` logs (`kubectl logs -n argocd deploy/argocd-notifications-controller`) and confirm that the application has the `notifications.argoproj.io/subscribe.on-flashduty-change.flashduty-change` annotation, or that `subscriptions` includes `on-flashduty-change` +- If the logs show `template 'flashduty-change' is not supported` or `trigger 'on-flashduty-change' is not configured`, confirm the configuration is in `argocd-notifications-cm`; for Helm installs, check the corresponding values + + + + + +When a sync finishes within a few seconds, Argo CD may not observe the `Running` phase and sends only the end notification. Flashduty records the change directly in its end state. + + + + + +No. An event with the same phase and the same time is recorded only once. + + + + + +Confirm the template matches this page and every value goes through `toJson`. The response names the missing or unsupported field, such as `app_uid is missing`, `started_at is missing`, or `unsupported phase`. + + + + +For related configuration, see the Argo CD documentation on [Webhook](https://argo-cd.readthedocs.io/en/stable/operator-manual/notifications/services/webhook/), [Triggers](https://argo-cd.readthedocs.io/en/stable/operator-manual/notifications/triggers/), [Templates](https://argo-cd.readthedocs.io/en/stable/operator-manual/notifications/templates/), and [Subscriptions](https://argo-cd.readthedocs.io/en/stable/operator-manual/notifications/subscriptions/). diff --git a/integration-docs/src/doc-map.mjs b/integration-docs/src/doc-map.mjs index e581768e1..bbb96a230 100644 --- a/integration-docs/src/doc-map.mjs +++ b/integration-docs/src/doc-map.mjs @@ -101,6 +101,7 @@ export const docMap = { CustomChange: `${integrationBase}/change-integration/custom-event.mdx`, GithubChange: `${integrationBase}/change-integration/github.mdx`, + ArgocdChange: `${integrationBase}/change-integration/argocd.mdx`, Jira: { zh: 'legacy/zh/jira-change.md', en: 'legacy/en/jira-change.md', diff --git a/zh/on-call/integration/change-integration/argocd.mdx b/zh/on-call/integration/change-integration/argocd.mdx new file mode 100644 index 000000000..d128b1119 --- /dev/null +++ b/zh/on-call/integration/change-integration/argocd.mdx @@ -0,0 +1,220 @@ +--- +title: "Argo CD 变更集成" +description: "通过 Argo CD Notifications 的 Webhook 服务将应用同步(Sync)操作同步到 Flashduty On-call,作为变更事件与告警、故障关联。" +keywords: ["变更集成", "Argo CD", "ArgoCD", "GitOps", "Sync", "Notifications", "Webhook", "部署事件"] +--- + +**版本要求**:此功能需要 On-call 标准版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/) + +Argo CD 通过内置的 **Notifications**(`argocd-notifications-controller`)推送变更:本集成提供一段 `argocd-notifications-cm` 配置,包含一个 Webhook 服务、一个请求体模板和一个触发器。Argo CD 应用(Application)的每一次同步(Sync)操作对应一条 Flashduty 变更,同步开始时记录为 Processing,结束时更新为 Done、Failed 或 Canceled。 + +自动同步、在界面或 CLI 中手动同步、回滚(Rollback)都是同步操作,都会记录。应用的同步失败、健康降级告警请使用 Argo CD 告警集成,两者可以同时配置。 + +
+ +## 在 Flashduty On-call +--- + +1. 进入 Flashduty 控制台,选择 **集成中心 → 变更事件** +2. 选择 **Argo CD**,填写集成名称 +3. 如需把变更分派到指定协作空间,在集成的 **路由** 中按标签(例如 `application`、`project`、`destination_namespace`)配置规则 +4. 点击 **保存**,复制生成的 **推送地址** + +
+ +## 在 Argo CD 中配置 +--- + +以下操作需要能修改 Argo CD 所在命名空间(默认 `argocd`)中 ConfigMap 的 Kubernetes 权限,以及修改 Application 或 AppProject 注解的权限。Argo CD 集群需要能访问推送地址所在的域名。 + + + + +把下面的内容保存为 `flashduty-change.yaml`,将 `url` 替换为上一步复制的推送地址(包含 `?integration_key=...`): + +```yaml +data: + service.webhook.flashduty-change: | + url: <推送地址> + headers: + - name: Content-Type + value: application/json + + template.flashduty-change: | + webhook: + flashduty-change: + method: POST + body: | + { + "app_uid": {{ .app.metadata.uid | toJson }}, + "app_name": {{ .app.metadata.name | toJson }}, + "app_namespace": {{ .app.metadata.namespace | toJson }}, + "project": {{ .app.spec.project | toJson }}, + "destination": {{ dig "spec" "destination" "name" (dig "spec" "destination" "server" "" .app) .app | toJson }}, + "destination_namespace": {{ dig "spec" "destination" "namespace" "" .app | toJson }}, + "argocd_url": {{ .context.argocdUrl | toJson }}, + "phase": {{ dig "status" "operationState" "phase" "" .app | toJson }}, + "message": {{ dig "status" "operationState" "message" "" .app | toJson }}, + "started_at": {{ dig "status" "operationState" "startedAt" "" .app | toJson }}, + "finished_at": {{ dig "status" "operationState" "finishedAt" "" .app | toJson }}, + "revision": {{ dig "status" "operationState" "syncResult" "revision" (dig "status" "operationState" "operation" "sync" "revision" "" .app) .app | toJson }}, + "initiated_by": {{ dig "status" "operationState" "operation" "initiatedBy" "username" "" .app | toJson }}, + "automated": {{ dig "status" "operationState" "operation" "initiatedBy" "automated" false .app | toJson }}, + "dry_run": {{ dig "status" "operationState" "operation" "sync" "dryRun" false .app | toJson }} + } + + trigger.on-flashduty-change: | + - when: app.status.operationState != nil and app.status.operationState.phase in ['Running'] + oncePer: app.status.operationState?.startedAt + send: [flashduty-change] + - when: app.status.operationState != nil and app.status.operationState.phase in ['Succeeded', 'Failed', 'Error'] + oncePer: app.status.operationState?.startedAt + send: [flashduty-change] +``` + +合并到现有的 `argocd-notifications-cm`(`--type merge` 只增改上面这些键,不影响已有配置): + +```bash +kubectl patch configmap argocd-notifications-cm -n argocd --type merge --patch-file flashduty-change.yaml +``` + +如果 Argo CD 通过 Helm Chart 安装,请把 `service.webhook.flashduty-change` 写到 `notifications.notifiers`,模板写到 `notifications.templates`,触发器写到 `notifications.triggers`,否则下次升级会覆盖手动修改。 + +配置说明: + +- 模板中的每个值都经过 `toJson` 转义,同步信息中的引号和换行不会破坏 JSON,请不要去掉。字段名不要修改,`app_uid`、`phase` 和 `started_at` 必须保留 +- 可选字段通过 `dig` 读取,应用从未同步过、同步尚未产生结果时模板也能正常渲染 +- 触发器的两个条件分别对应同步开始和同步结束。`oncePer` 取同步操作的开始时间,保证每一次同步操作的开始和结束各发送一次,即使连续两次同步之间 Argo CD 没有观察到中间状态,请不要去掉 +- 服务名 `flashduty-change` 与告警集成使用的 `flashduty` 不同,两个集成的推送地址互不影响 +- `argocd_url` 取自 `argocd-notifications-cm` 的 `context.argocdUrl`,用于生成变更链接;未配置时变更没有链接,不影响记录 + + + + + +触发器需要被订阅后才会发送。按需要的范围选择一种方式: + +- **单个应用**:在 Application 上添加注解 + + ```bash + kubectl patch application <应用名> -n argocd --type merge \ + -p '{"metadata":{"annotations":{"notifications.argoproj.io/subscribe.on-flashduty-change.flashduty-change":""}}}' + ``` + +- **一个项目下的所有应用**:在 AppProject 的 `metadata.annotations` 中添加同样的注解 `notifications.argoproj.io/subscribe.on-flashduty-change.flashduty-change: ""` +- **所有应用**:在 `argocd-notifications-cm` 的 `subscriptions` 中添加一项。如果已有 `subscriptions`(例如告警集成添加的那一项),请在原列表中追加,不要用上一步的 merge 命令整体覆盖 + + ```yaml + subscriptions: | + - recipients: + - flashduty-change + triggers: + - on-flashduty-change + ``` + +订阅生效时,已经同步过的应用会立即发送一次最近一次同步的结果,Flashduty 会按该次同步原本的开始、结束时间记录为一条变更。 + + + + + +Argo CD 没有发送测试消息的按钮。可以在 `argocd-notifications-controller` Pod 中用 `argocd admin notifications template notify` 按应用当前状态发送一次通知: + +```bash +kubectl exec -n argocd deploy/argocd-notifications-controller -- \ + /usr/local/bin/argocd admin notifications template notify flashduty-change <应用名> --recipient flashduty-change +``` + +命令没有输出错误即表示 Flashduty 已接受请求。应用同步过时,这条通知就是最近一次同步的结果,与该次同步已有的记录合并,不会新增变更;应用从未同步过时,Flashduty 直接忽略。 + + + + + +同步一个已订阅的应用(在界面点击 **Sync**,或执行 `argocd app sync <应用名>`),确认 Flashduty 的变更列表中出现一条 Processing 的变更,同步结束后更新为 Done 或 Failed。 + + + + +## 一条变更是什么 +--- + +一条变更对应一个应用的一次同步操作,变更标识(change_key)为 `/`: + +- `app_uid` 是应用的 `metadata.uid`。Kubernetes 为每个对象分配的 UID 在集群的整个生命周期内唯一,不同 Argo CD 实例中同名的应用、删除后重建的应用都是不同的应用 +- `started_at` 是同步操作的开始时间(`status.operationState.startedAt`,按 UTC 记录)。Argo CD 在同步开始时写入这个时间,重试期间保持不变,一个应用同一时刻只运行一个同步操作 + +因此同一次同步的开始、失败重试和最终结果更新同一条变更;同一个应用的两次同步是两条变更,即使同步的是同一个版本。应用名称、项目、版本和同步信息的变化不会改变变更标识。 + +请求缺少 `app_uid` 或 `started_at`,或者时间不是 RFC 3339 格式时,Flashduty 会拒绝该请求。 + +## 状态映射 +--- + +| Argo CD 同步阶段(`phase`) | Flashduty 变更状态 | +|---|---| +| `Running`、`Terminating` | Processing | +| `Succeeded` | Done | +| `Failed`、`Error` | Failed | +| `Failed`,信息为 `Operation terminated`(在界面点击 **Terminate** 或执行 `argocd app terminate-op`) | Canceled | + +Done、Failed 和 Canceled 是结束状态,Flashduty 会记录变更结束时间。因同步超时被 Argo CD 终止的操作(信息包含 `triggered by controller sync timeout`)记为 Failed。 + +同步阶段区分大小写,其他值会被拒绝。以下推送返回成功但不生成变更:应用还没有同步操作(`phase` 为空)、试运行(Dry Run)同步。 + +同步开始时记录的时间是 `started_at`,结束时是 `finished_at`。Argo CD 失败后自动重试期间,同步阶段保持 `Running`,不会提前记为 Failed。 + +## 变更内容 +--- + +- **标题**:`<应用名>: sync <版本> to <目标命名空间>`。版本为 Git 提交时显示前 7 位,Helm Chart 版本等其他值原样显示;没有版本或目标命名空间时省略对应部分 +- **链接**:`/applications/<应用名>`,配置了 `context.argocdUrl` 时才有 + +标签可用于路由和在变更列表中筛选: + +| 标签 | 说明 | +|---|---| +| `application` | 应用名 | +| `app_uid` | 应用的 `metadata.uid` | +| `app_namespace` | Application 对象所在的命名空间 | +| `project` | 应用所属的 Argo CD 项目 | +| `destination` | 目标集群名称,未设置名称时为集群地址 | +| `destination_namespace` | 目标命名空间 | +| `revision` | 同步的版本(Git 提交或 Chart 版本) | +| `actor` | 发起同步的用户;自动同步为 `automated` | +| `phase` | 最新的同步阶段 | +| `message` | 最新的同步信息,例如失败原因,超过 1024 字节时截断 | + +值为空的字段不会写入标签。 + +## 常见问题 +--- + + + + +- 查看 `argocd-notifications-controller` 的日志(`kubectl logs -n argocd deploy/argocd-notifications-controller`),确认应用上有 `notifications.argoproj.io/subscribe.on-flashduty-change.flashduty-change` 注解,或 `subscriptions` 中包含 `on-flashduty-change` +- 日志中出现 `template 'flashduty-change' is not supported` 或 `trigger 'on-flashduty-change' is not configured` 时,确认配置已写入 `argocd-notifications-cm`,Helm 安装请检查对应的 values + + + + + +同步在几秒内完成时,Argo CD 可能没有观察到 `Running` 阶段,只发送结束通知。Flashduty 会直接按结束状态记录这条变更。 + + + + + +不会。同一阶段、同一时间的事件只记录一次。 + + + + + +确认模板与本文一致,所有值都经过 `toJson`。响应内容会指出缺少或不支持的字段,例如 `app_uid is missing`、`started_at is missing`、`unsupported phase`。 + + + + +相关配置请参阅 Argo CD 文档 [Webhook](https://argo-cd.readthedocs.io/en/stable/operator-manual/notifications/services/webhook/)、[Triggers](https://argo-cd.readthedocs.io/en/stable/operator-manual/notifications/triggers/)、[Templates](https://argo-cd.readthedocs.io/en/stable/operator-manual/notifications/templates/) 和 [Subscriptions](https://argo-cd.readthedocs.io/en/stable/operator-manual/notifications/subscriptions/)。 From c1bae38310edb5dd499905067dde77391003e57b Mon Sep 17 00:00:00 2001 From: ysyneu Date: Mon, 28 Sep 2026 09:56:07 -0700 Subject: [PATCH 11/36] docs(change): note the Netlify link fallback --- en/on-call/integration/change-integration/netlify.mdx | 2 +- zh/on-call/integration/change-integration/netlify.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/en/on-call/integration/change-integration/netlify.mdx b/en/on-call/integration/change-integration/netlify.mdx index 0cd347050..9c94bad0b 100644 --- a/en/on-call/integration/change-integration/netlify.mdx +++ b/en/on-call/integration/change-integration/netlify.mdx @@ -89,7 +89,7 @@ Done, Failed, and Canceled are end states; Flashduty records the change's end ti |---|---| | Title | `: deploy () to `, such as `example-site: deploy main (f95f852) to production`; a manual deploy without a branch or commit gives `: deploy to ` | | Description | The deploy's title, usually the commit message or the message entered for a manual deploy | -| Link | The deploy's page in the Netlify console | +| Link | The deploy's page in the Netlify console, or the deploy's own URL when the payload has no `admin_url` | Labels can be used in routes and to filter the change list: diff --git a/zh/on-call/integration/change-integration/netlify.mdx b/zh/on-call/integration/change-integration/netlify.mdx index 091ce101f..15260bace 100644 --- a/zh/on-call/integration/change-integration/netlify.mdx +++ b/zh/on-call/integration/change-integration/netlify.mdx @@ -89,7 +89,7 @@ Done、Failed 和 Canceled 是结束状态,Flashduty 会记录变更结束时 |---|---| | 标题 | `<项目名>: deploy <分支> (<短 SHA>) to <部署上下文>`,例如 `example-site: deploy main (f95f852) to production`;手动部署没有分支和提交时为 `<项目名>: deploy to <部署上下文>` | | 描述 | 部署的 title,通常是提交信息或手动部署时填写的说明 | -| 链接 | Netlify 控制台中这次部署的页面 | +| 链接 | Netlify 控制台中这次部署的页面;推送中没有 `admin_url` 时为这次部署的访问地址 | 标签可用于路由和在变更列表中筛选: From 67ce6150ad02c1a941afb2948e574cdb30689d6f Mon Sep 17 00:00:00 2001 From: ysyneu Date: Mon, 28 Sep 2026 09:58:20 -0700 Subject: [PATCH 12/36] docs: add JFrog Artifactory change integration page --- docs.json | 6 +- .../change-integration/jfrog-artifactory.mdx | 137 ++++++++++++++++++ integration-docs/src/doc-map.mjs | 1 + .../change-integration/jfrog-artifactory.mdx | 137 ++++++++++++++++++ 4 files changed, 279 insertions(+), 2 deletions(-) create mode 100644 en/on-call/integration/change-integration/jfrog-artifactory.mdx create mode 100644 zh/on-call/integration/change-integration/jfrog-artifactory.mdx diff --git a/docs.json b/docs.json index 37d503c6c..2d9bd5f7a 100644 --- a/docs.json +++ b/docs.json @@ -1775,7 +1775,8 @@ "group": "变更集成", "pages": [ "zh/on-call/integration/change-integration/custom-event", - "zh/on-call/integration/change-integration/github" + "zh/on-call/integration/change-integration/github", + "zh/on-call/integration/change-integration/jfrog-artifactory" ] }, { @@ -3174,7 +3175,8 @@ "group": "Change Integration", "pages": [ "en/on-call/integration/change-integration/custom-event", - "en/on-call/integration/change-integration/github" + "en/on-call/integration/change-integration/github", + "en/on-call/integration/change-integration/jfrog-artifactory" ] }, { diff --git a/en/on-call/integration/change-integration/jfrog-artifactory.mdx b/en/on-call/integration/change-integration/jfrog-artifactory.mdx new file mode 100644 index 000000000..4dcee68dd --- /dev/null +++ b/en/on-call/integration/change-integration/jfrog-artifactory.mdx @@ -0,0 +1,137 @@ +--- +title: "JFrog Artifactory change integration" +description: "Sync artifact deploys, deletes, moves, and copies from JFrog Artifactory to Flashduty On-call through a webhook, as change events you can correlate with alerts and incidents." +keywords: ["change integration", "JFrog", "Artifactory", "artifact", "Webhook", "change events"] +--- + +**Plan requirement**: This feature requires an On-call Standard or higher subscription. [Learn more](https://flashcat.cloud/flashduty/price/) + +Use a JFrog Artifactory predefined webhook to sync artifact deploys, deletes, moves, and copies to Flashduty On-call. Each deployed artifact becomes one change, and deleting that same artifact later updates the change to Canceled; each move or copy becomes a change of its own. + +
+ +## In Flashduty On-call +--- + +1. In the Flashduty console, go to **Integration Center → Change Events** +2. Select **JFrog Artifactory** and enter an integration name +3. To assign changes to specific channels, add rules under the integration's **Routes** that match labels such as `repo` or `path` +4. Click **Save** and copy the generated **Push URL** + +
+ +## Configure JFrog Artifactory +--- + + + + +1. Sign in to the JFrog Platform and select **All Projects** or a specific project +2. Go to **Platform → Integrations → Webhooks** and click **New Webhook** +3. Keep the **Predefined** toggle selected (do not use Custom) + +You need admin or project admin permission. + + + + + +1. **Name**: for example, `flashduty-changes` +2. **URL**: paste the complete Flashduty integration Push URL +3. **Secret token**: leave empty; Flashduty authenticates with the `integration_key` in the Push URL + + + + + +1. Under **Artifacts**, select **Artifact was deployed**, **Artifact was deleted**, **Artifact was moved**, and **Artifact was copied** +2. Select the repositories to watch: all local repositories, a list of repositories, or include/exclude path patterns +3. Click **Test** to check connectivity, then click **Create** + +**Test** sends JFrog's sample data (checksum `sample_checksum`); Flashduty returns success but records no change. + + + + +## What one change is +--- + +JFrog payloads carry no change ID, so Flashduty identifies an artifact by its location plus its content checksum: + +| Artifactory event | Change key (change_key) | Notes | +|---|---|---| +| deployed, deleted | `artifact:/@` | Deploying and later deleting the same content update the same change; new content at the same path (a different checksum) is a new change | +| moved | `moved:/@ -> ` | One change per move | +| copied | `copied:/@ -> ` | One change per copy | + +For moved and copied, `/` is the artifact's original location and `` is the payload's `target_repo_path`. + +## Status mapping +--- + +| Artifactory event (event_type) | Flashduty change status | +|---|---| +| deployed | Done | +| moved | Done | +| copied | Done | +| deleted | Canceled | + +Artifactory sends artifact events after the operation completes, so each change has already ended when its first event arrives. + +The following deliveries return success but record no change: event domains other than artifacts (Artifact Properties, Docker, Builds, Release Bundles, and so on), `cached` (a remote repository caching a downloaded artifact, which is not a change), and the sample data sent by the **Test** button. + +## Change content +--- + +| Field | deployed, deleted | moved, copied | +|---|---|---| +| Title | `/ ()` | `move / () to `, or `copy ...` for a copy | +| Description | Empty | Empty | +| Link | The artifact's page in the JFrog Platform | The target location's page in the JFrog Platform | + +The link is built from the payload's `jpd_origin`; when the payload has no such field, the change has no link. + +Labels can be used in routes and to filter the change list: + +| Label | Description | +|---|---| +| `repo` | Repository key; for moved and copied, the original repository | +| `path` | The artifact's path in the repository | +| `name` | File name | +| `sha256` | SHA-256 checksum of the artifact's content | +| `source_repo_path` | moved and copied only: the original location | +| `target_repo_path` | moved and copied only: the target location | +| `actor` | The user or access token subject that performed the operation | +| `event_type` | Artifactory event: `deployed`, `deleted`, `moved`, or `copied` | + +## FAQ +--- + + + + +- Make sure the webhook is **Predefined** and has events under **Artifacts** selected +- Make sure the repository you deploy to is within the webhook's selected repositories +- Check the delivery records and Flashduty's responses on the webhook's **Troubleshooting** tab (on JFrog Cloud, the instance must have this feature enabled) + + + + + +Deploying a file with identical content to the same path adds an event to the existing change instead of creating a new one. Different content creates a new change. + + + + + +A retry adds an event but does not create a new change. JFrog payloads carry no event time, so Flashduty records each event at the time it is received and cannot recognize a retry. + + + + + +- `unsupported event_type`: Flashduty received an artifact event it does not support yet; contact us +- `data.repo_key is missing`, `data.path is missing`, `data.sha256 is missing`, or `data.target_repo_path is missing`: the payload is incomplete; make sure you use a Predefined webhook, not a Custom webhook with a customized payload + + + diff --git a/integration-docs/src/doc-map.mjs b/integration-docs/src/doc-map.mjs index e581768e1..75ad94e65 100644 --- a/integration-docs/src/doc-map.mjs +++ b/integration-docs/src/doc-map.mjs @@ -101,6 +101,7 @@ export const docMap = { CustomChange: `${integrationBase}/change-integration/custom-event.mdx`, GithubChange: `${integrationBase}/change-integration/github.mdx`, + JfrogArtifactoryChange: `${integrationBase}/change-integration/jfrog-artifactory.mdx`, Jira: { zh: 'legacy/zh/jira-change.md', en: 'legacy/en/jira-change.md', diff --git a/zh/on-call/integration/change-integration/jfrog-artifactory.mdx b/zh/on-call/integration/change-integration/jfrog-artifactory.mdx new file mode 100644 index 000000000..1f53828d4 --- /dev/null +++ b/zh/on-call/integration/change-integration/jfrog-artifactory.mdx @@ -0,0 +1,137 @@ +--- +title: "JFrog Artifactory 变更集成" +description: "通过 JFrog Artifactory Webhook 将制品的上传、删除、移动和复制同步到 Flashduty On-call,作为变更事件与告警、故障关联。" +keywords: ["变更集成", "JFrog", "Artifactory", "制品", "Webhook", "变更事件"] +--- + +**版本要求**:此功能需要 On-call 标准版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/) + +通过 JFrog Artifactory 的预定义(Predefined)Webhook,将制品(Artifact)的上传、删除、移动和复制同步到 Flashduty On-call。每上传一个制品生成一条变更,之后删除同一个制品会把这条变更更新为已取消;每次移动或复制生成一条独立的变更。 + +
+ +## 在 Flashduty On-call +--- + +1. 进入 Flashduty 控制台,选择 **集成中心 → 变更事件** +2. 选择 **JFrog Artifactory**,填写集成名称 +3. 如需把变更分派到指定协作空间,在集成的 **路由** 中按标签(例如 `repo`、`path`)配置规则 +4. 点击 **保存**,复制生成的 **推送地址** + +
+ +## 在 JFrog Artifactory 中配置 +--- + + + + +1. 登录 JFrog Platform,选择 **All Projects** 或某个项目 +2. 进入 **Platform → Integrations → Webhooks**,点击 **New Webhook** +3. 保持 **Predefined** 开关选中(不要使用 Custom) + +需要管理员或项目管理员权限。 + + + + + +1. **Name**:例如 `flashduty-changes` +2. **URL**:粘贴 Flashduty 集成的完整推送地址 +3. **Secret token**:留空即可,Flashduty 通过推送地址中的 `integration_key` 鉴权 + + + + + +1. 在事件列表中选择 **Artifacts** 下的 **Artifact was deployed**、**Artifact was deleted**、**Artifact was moved** 和 **Artifact was copied** +2. 选择要监听的仓库:可选择全部本地仓库,也可以指定仓库或用包含/排除规则按路径筛选 +3. 点击 **Test** 检查连通性,再点击 **Create** + +**Test** 发送的是 JFrog 的示例数据(校验和为 `sample_checksum`),Flashduty 返回成功但不会生成变更。 + + + + +## 一条变更是什么 +--- + +JFrog 的推送内容里没有变更 ID,Flashduty 用制品所在位置加内容校验和标识一个制品: + +| Artifactory 事件 | 变更标识(change_key) | 说明 | +|---|---|---| +| deployed、deleted | `artifact:<仓库>/<路径>@` | 上传和之后删除同一份内容更新同一条变更;同一路径上传了新内容(校验和不同)是一条新变更 | +| moved | `moved:<仓库>/<路径>@ -> <目标>` | 一次移动一条变更 | +| copied | `copied:<仓库>/<路径>@ -> <目标>` | 一次复制一条变更 | + +对 moved 和 copied,`<仓库>/<路径>` 是制品原来的位置,`<目标>` 是推送中的 `target_repo_path`。 + +## 状态映射 +--- + +| Artifactory 事件(event_type) | Flashduty 变更状态 | +|---|---| +| deployed | Done | +| moved | Done | +| copied | Done | +| deleted | Canceled | + +Artifactory 的制品事件都在操作完成后推送,因此每条变更收到第一个事件时就已结束。 + +以下推送返回成功但不生成变更:制品以外的事件域(Artifact Properties、Docker、Builds、Release Bundles 等)、`cached`(远程仓库缓存了一个下载的制品,不是变更)、**Test** 按钮发送的示例数据。 + +## 变更内容 +--- + +| 字段 | deployed、deleted | moved、copied | +|---|---|---| +| 标题 | `<仓库>/<路径> ()` | `move <仓库>/<路径> () to <目标>`,复制时为 `copy ...` | +| 描述 | 空 | 空 | +| 链接 | JFrog Platform 中该制品的页面 | JFrog Platform 中目标位置的页面 | + +链接由推送中的 `jpd_origin` 生成;推送中没有该字段时变更没有链接。 + +标签可用于路由和在变更列表中筛选: + +| 标签 | 说明 | +|---|---| +| `repo` | 仓库名(Repository Key);moved、copied 时为原仓库 | +| `path` | 制品在仓库中的路径 | +| `name` | 文件名 | +| `sha256` | 制品内容的 SHA-256 校验和 | +| `source_repo_path` | 仅 moved、copied:原位置 | +| `target_repo_path` | 仅 moved、copied:目标位置 | +| `actor` | 执行操作的用户或访问令牌主体 | +| `event_type` | Artifactory 事件:`deployed`、`deleted`、`moved` 或 `copied` | + +## 常见问题 +--- + + + + +- 确认 Webhook 是 **Predefined** 类型,并勾选了 **Artifacts** 下的事件 +- 确认上传的仓库在 Webhook 选择的仓库范围内 +- 在 Webhook 的 **Troubleshooting** 页查看推送记录和 Flashduty 的响应(JFrog Cloud 需要实例开启该功能) + + + + + +把内容完全相同的文件再次上传到同一路径,会在原来那条变更上追加一个事件,不会生成新变更。内容不同则生成新变更。 + + + + + +会追加一个事件,但不会生成新变更。JFrog 的推送内容不带事件时间,Flashduty 以收到推送的时间记录每个事件,因此无法识别重试。 + + + + + +- `unsupported event_type`:收到了 Flashduty 尚未支持的制品事件,请联系我们 +- `data.repo_key is missing`、`data.path is missing`、`data.sha256 is missing` 或 `data.target_repo_path is missing`:推送内容不完整,请确认使用的是 Predefined Webhook,而不是自定义了推送内容的 Custom Webhook + + + From 90f632a7ec77fe496fd806182a138347381a7a5d Mon Sep 17 00:00:00 2001 From: ysyneu Date: Mon, 28 Sep 2026 09:58:47 -0700 Subject: [PATCH 13/36] docs(change): add Vercel change integration page --- docs.json | 6 +- .../integration/change-integration/vercel.mdx | 139 ++++++++++++++++++ integration-docs/src/doc-map.mjs | 1 + .../integration/change-integration/vercel.mdx | 139 ++++++++++++++++++ 4 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 en/on-call/integration/change-integration/vercel.mdx create mode 100644 zh/on-call/integration/change-integration/vercel.mdx diff --git a/docs.json b/docs.json index 37d503c6c..837329c9b 100644 --- a/docs.json +++ b/docs.json @@ -1775,7 +1775,8 @@ "group": "变更集成", "pages": [ "zh/on-call/integration/change-integration/custom-event", - "zh/on-call/integration/change-integration/github" + "zh/on-call/integration/change-integration/github", + "zh/on-call/integration/change-integration/vercel" ] }, { @@ -3174,7 +3175,8 @@ "group": "Change Integration", "pages": [ "en/on-call/integration/change-integration/custom-event", - "en/on-call/integration/change-integration/github" + "en/on-call/integration/change-integration/github", + "en/on-call/integration/change-integration/vercel" ] }, { diff --git a/en/on-call/integration/change-integration/vercel.mdx b/en/on-call/integration/change-integration/vercel.mdx new file mode 100644 index 000000000..89a2c07b2 --- /dev/null +++ b/en/on-call/integration/change-integration/vercel.mdx @@ -0,0 +1,139 @@ +--- +title: "Vercel change integration" +description: "Sync deployments, promotions and rollbacks from a Vercel team webhook to Flashduty On-call as change events correlated with alerts and incidents." +keywords: ["change integration", "Vercel", "Deployment", "deployment events", "Instant Rollback", "Webhook"] +--- + +**Plan requirement**: This feature requires the On-call Standard plan or above. [Learn more](https://flashcat.cloud/flashduty/price/) + +Use a Vercel team webhook to sync deployments and production rollbacks (Instant Rollback) to Flashduty On-call. Each deployment becomes one Flashduty change; every state of the deployment, from created and built to succeeded, promoted, failed or canceled, updates that same change. + +Vercel team webhooks are available to Pro and Enterprise teams only; Hobby accounts cannot configure them. + +
+ +## In Flashduty On-call +--- + +1. In the Flashduty console, go to **Integration Center → Change Events** +2. Select **Vercel** and enter an integration name +3. To assign changes to specific channels, configure rules in the integration's **Routing** based on labels such as `project` or `environment` +4. Click **Save** and copy the generated **Push URL** + +
+ +## In Vercel +--- + + + + +In the Vercel dashboard, switch to the target team and go to **Settings → Webhooks**. You need permission to manage the team's webhooks. + + + + + +Under **Deployment Events**, select: + +- **Deployment Created** +- **Deployment Succeeded** +- **Deployment Promoted** +- **Deployment Rollback** +- **Deployment Error** +- **Deployment Cancelled** + +Project, Feature Flag and Firewall events are not deployment changes; if selected, Flashduty returns success without recording a change. + + + + + +1. Choose the projects to send: **All Team Projects** or specific projects +2. **Endpoint URL**: paste the full Flashduty push URL +3. Click **Create Webhook** + +Vercel then shows a secret. Flashduty does not need it; requests are authenticated by the `integration_key` in the push URL. + + + + +## What one change is +--- + +| Vercel object | Change key (change_key) | Notes | +|---|---|---| +| Deployment | `deployment:` | Every event of one deployment (an ID starting with `dpl_`) updates the same change; two deployments of the same project and commit are two changes | +| Rollback | `rollback::` | An Instant Rollback is a separate change and does not modify the records of the replaced or restored deployment | + +## Status mapping +--- + +| Vercel event | Flashduty change status | +|---|---| +| `deployment.created` | Ready | +| `deployment.ready` (built, checks running) | Processing | +| `deployment.succeeded` | Done | +| `deployment.promoted` (now serving production traffic) | Done | +| `deployment.error` | Failed | +| `deployment.canceled` | Canceled | +| `deployment.rollback` | Done | + +Done, Failed and Canceled are end states; Flashduty records the change's end time. + +These deliveries return success without recording a change: event types that do not start with `deployment.` (Project, Feature Flag, Firewall and others); deployment events about checks or integration actions; `deployment.cleanup` (the deployment is permanently deleted after its retention period, which does not change its earlier result). + +## Change content +--- + +| Field | Deployment | Rollback | +|---|---|---| +| Title | `: deploy () to `, or the deployment URL when there is no Git metadata | `: roll back production to ` | +| Description | First line of the Git commit message | Empty | +| Link | The deployment's page in the Vercel dashboard | Empty (Vercel rollback events carry no link) | + +Labels can be used for routing and for filtering the change list: + +| Label | Deployment | Rollback | +|---|---|---| +| `project` | Project name | — | +| `project_id` | Project ID (starts with `prj_`) | Same | +| `environment` | `production`, a custom environment such as `staging`, or `preview` when no target is set | `production` | +| `ref` | Git branch | — | +| `sha` | Full commit SHA | — | +| `actor` | Git username of the commit author | — | +| `deployment_id` | Deployment ID | — | +| `from_deployment_id` / `to_deployment_id` | — | IDs of the replaced / restored deployment | +| `state` | Latest Vercel event, for example `succeeded` | `rollback` | + +`ref`, `sha` and `actor` come from the deployment metadata of a connected GitHub, GitLab or Bitbucket repository; deployments made directly from the CLI do not have them. + +## FAQ +--- + + + + +After a production deployment builds successfully, Vercel sends `deployment.succeeded`, then `deployment.promoted` once production traffic has switched to it. Both map to Done and update the same change. + + + + + +No. Flashduty uses the time carried by the Vercel event, so the same event at the same time is recorded once. When a delivery fails, Vercel retries it for up to 24 hours. + + + + + +Rolling back from the same deployment to the same deployment produces the same change key, so the second rollback updates the first rollback's change (its last time becomes the second rollback's time) instead of creating a new one. Vercel rollback events carry only the two deployment IDs, not a rollback ID of their own. + + + + + +- `unsupported type`: Flashduty received a deployment event it does not support yet (for example `deployment.blocked` subscribed through the API). Select only the six events listed above, or contact us +- `payload.deployment.id is missing`: the payload is incomplete; make sure the request comes from a native Vercel webhook + + + diff --git a/integration-docs/src/doc-map.mjs b/integration-docs/src/doc-map.mjs index e581768e1..e73b40db3 100644 --- a/integration-docs/src/doc-map.mjs +++ b/integration-docs/src/doc-map.mjs @@ -101,6 +101,7 @@ export const docMap = { CustomChange: `${integrationBase}/change-integration/custom-event.mdx`, GithubChange: `${integrationBase}/change-integration/github.mdx`, + VercelChange: `${integrationBase}/change-integration/vercel.mdx`, Jira: { zh: 'legacy/zh/jira-change.md', en: 'legacy/en/jira-change.md', diff --git a/zh/on-call/integration/change-integration/vercel.mdx b/zh/on-call/integration/change-integration/vercel.mdx new file mode 100644 index 000000000..d616b904a --- /dev/null +++ b/zh/on-call/integration/change-integration/vercel.mdx @@ -0,0 +1,139 @@ +--- +title: "Vercel 变更集成" +description: "通过 Vercel 团队 Webhook 将部署、上线和回滚同步到 Flashduty On-call,作为变更事件与告警、故障关联。" +keywords: ["变更集成", "Vercel", "Deployment", "部署事件", "Instant Rollback", "Webhook"] +--- + +**版本要求**:此功能需要 On-call 标准版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/) + +通过 Vercel 团队的 Webhook,将部署(Deployment)和生产环境回滚(Instant Rollback)同步到 Flashduty On-call。每一次部署对应一条 Flashduty 变更,部署从创建、构建到成功、上线、失败或取消的每个状态,都会更新同一条变更。 + +Vercel 的团队 Webhook 仅对 Pro 和 Enterprise 团队开放,Hobby 账号无法配置。 + +
+ +## 在 Flashduty On-call +--- + +1. 进入 Flashduty 控制台,选择 **集成中心 → 变更事件** +2. 选择 **Vercel**,填写集成名称 +3. 如需把变更分派到指定协作空间,在集成的 **路由** 中按标签(例如 `project`、`environment`)配置规则 +4. 点击 **保存**,复制生成的 **推送地址** + +
+ +## 在 Vercel 中配置 +--- + + + + +在 Vercel 控制台切换到目标团队,进入 **Settings → Webhooks**。需要团队的 Webhook 管理权限。 + + + + + +在 **Deployment Events** 中勾选: + +- **Deployment Created** +- **Deployment Succeeded** +- **Deployment Promoted** +- **Deployment Rollback** +- **Deployment Error** +- **Deployment Cancelled** + +Project、Feature Flag、Firewall 事件不是部署变更,勾选后 Flashduty 返回成功但不会生成变更。 + + + + + +1. 选择要推送的项目:**All Team Projects** 或指定项目 +2. **Endpoint URL**:粘贴 Flashduty 集成的完整推送地址 +3. 点击 **Create Webhook** + +Vercel 创建后会显示一个 Secret,Flashduty 不需要它,通过推送地址中的 `integration_key` 鉴权。 + + + + +## 一条变更是什么 +--- + +| Vercel 对象 | 变更标识(change_key) | 说明 | +|---|---|---| +| 部署 | `deployment:` | 同一次部署(`dpl_` 开头的 ID)的所有事件更新同一条变更;同一项目、同一提交的两次部署是两条变更 | +| 回滚 | `rollback::` | 一次 Instant Rollback 是一条独立变更,不修改被替换或被恢复的部署的记录 | + +## 状态映射 +--- + +| Vercel 事件 | Flashduty 变更状态 | +|---|---| +| `deployment.created` | Ready | +| `deployment.ready`(构建完成,Checks 执行中) | Processing | +| `deployment.succeeded` | Done | +| `deployment.promoted`(开始承接生产流量) | Done | +| `deployment.error` | Failed | +| `deployment.canceled` | Canceled | +| `deployment.rollback` | Done | + +Done、Failed 和 Canceled 是结束状态,Flashduty 会记录变更结束时间。 + +以下推送返回成功但不生成变更:非 `deployment.` 开头的事件类型(Project、Feature Flag、Firewall 等);与 Checks、集成动作相关的部署事件;`deployment.cleanup`(部署在保留期结束后被永久删除,不改变该部署已有的结果)。 + +## 变更内容 +--- + +| 字段 | 部署 | 回滚 | +|---|---|---| +| 标题 | `<项目>: deploy <分支> (<短 SHA>) to <环境>`,没有 Git 信息时为部署域名 | `<项目 ID>: roll back production to <恢复的部署 ID>` | +| 描述 | Git 提交信息的第一行 | 空 | +| 链接 | Vercel 控制台中该部署的页面 | 空(Vercel 回滚事件不带链接) | + +标签可用于路由和在变更列表中筛选: + +| 标签 | 部署 | 回滚 | +|---|---|---| +| `project` | 项目名称 | — | +| `project_id` | 项目 ID(`prj_` 开头) | 同左 | +| `environment` | `production`、自定义环境(例如 `staging`),未指定目标时为 `preview` | `production` | +| `ref` | Git 分支 | — | +| `sha` | 完整提交 SHA | — | +| `actor` | 提交者的 Git 用户名 | — | +| `deployment_id` | 部署 ID | — | +| `from_deployment_id` / `to_deployment_id` | — | 被替换 / 被恢复的部署 ID | +| `state` | 最新的 Vercel 事件,例如 `succeeded` | `rollback` | + +`ref`、`sha`、`actor` 来自连接 GitHub、GitLab 或 Bitbucket 仓库时的部署元数据,通过 CLI 直接部署时没有这些标签。 + +## 常见问题 +--- + + + + +生产部署构建成功后 Vercel 先发送 `deployment.succeeded`,切换生产流量后再发送 `deployment.promoted`。两者都是 Done,更新的是同一条变更。 + + + + + +不会。Flashduty 使用 Vercel 事件自带的时间,同一事件、同一时间只记录一次。推送失败时 Vercel 会在 24 小时内重试。 + + + + + +从同一个部署回滚到同一个部署时变更标识相同,第二次回滚会更新第一次的变更(最后时间更新为第二次),不会新建变更。Vercel 的回滚事件只带两个部署 ID,没有独立的回滚 ID。 + + + + + +- `unsupported type`:收到了 Flashduty 尚未支持的部署事件(例如通过 API 订阅的 `deployment.blocked`),请只勾选上文列出的 6 个事件,或联系我们 +- `payload.deployment.id is missing`:推送内容不完整,请确认推送来自 Vercel 原生 Webhook + + + From 58152469d6ccca3a1fd03805830b5c26f6d15914 Mon Sep 17 00:00:00 2001 From: ysyneu Date: Mon, 28 Sep 2026 09:58:50 -0700 Subject: [PATCH 14/36] docs(change): note deleted scheduled changes are ignored --- en/on-call/integration/change-integration/launchdarkly.mdx | 2 +- zh/on-call/integration/change-integration/launchdarkly.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/en/on-call/integration/change-integration/launchdarkly.mdx b/en/on-call/integration/change-integration/launchdarkly.mdx index 31272e9a4..6294e000c 100644 --- a/en/on-call/integration/change-integration/launchdarkly.mdx +++ b/en/on-call/integration/change-integration/launchdarkly.mdx @@ -83,7 +83,7 @@ These deliveries are accepted without creating a change: - Entries for other resource kinds, such as projects, environments, members, roles, webhooks, metrics, and experiments - Entries that contain only the following actions, which do not change how a flag evaluates: - Creating, updating, reviewing, or deleting an approval request (once an approval request is applied, LaunchDarkly sends the entry for that step) - - Creating or updating scheduled changes (the entry for the scheduled change is sent when it runs) + - Creating, updating, or deleting scheduled changes (the entry for the scheduled change is sent when it runs) - Name, description, tags, maintainer, temporary flag, deprecation, custom properties, rule descriptions, code references, flag links, followers, and segment exports ## Change content diff --git a/zh/on-call/integration/change-integration/launchdarkly.mdx b/zh/on-call/integration/change-integration/launchdarkly.mdx index 0e16b8903..832a4402f 100644 --- a/zh/on-call/integration/change-integration/launchdarkly.mdx +++ b/zh/on-call/integration/change-integration/launchdarkly.mdx @@ -83,7 +83,7 @@ LaunchDarkly 没有测试推送按钮。保存后在任一 Flag 上做一次变 - 其他资源类型的记录,例如项目、环境、成员、角色、Webhook、指标、实验 - 只包含以下动作的记录,它们不改变 Flag 的求值结果: - 审批请求的创建、修改、评审、删除(审批通过并应用后,LaunchDarkly 会推送应用这一步的记录) - - 定时变更的创建和修改(到期执行时会推送执行的记录) + - 定时变更的创建、修改和删除(到期执行时会推送执行的记录) - 名称、描述、标签、维护者、临时标记、弃用标记、自定义属性、规则描述、代码引用、Flag 链接、关注者、Segment 导出 ## 变更内容 From bd95e26ce798f858930d945fc78dfd63a3221296 Mon Sep 17 00:00:00 2001 From: ysyneu Date: Mon, 28 Sep 2026 10:00:11 -0700 Subject: [PATCH 15/36] docs(change): add Jenkins change integration page Document the Jenkins change integration built on the Notification plugin: setup, what one change is, status mapping, labels and FAQ. --- docs.json | 6 +- .../change-integration/jenkins.mdx | 139 ++++++++++++++++++ integration-docs/src/doc-map.mjs | 1 + .../change-integration/jenkins.mdx | 139 ++++++++++++++++++ 4 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 en/on-call/integration/change-integration/jenkins.mdx create mode 100644 zh/on-call/integration/change-integration/jenkins.mdx diff --git a/docs.json b/docs.json index 37d503c6c..aa86e6cbe 100644 --- a/docs.json +++ b/docs.json @@ -1775,7 +1775,8 @@ "group": "变更集成", "pages": [ "zh/on-call/integration/change-integration/custom-event", - "zh/on-call/integration/change-integration/github" + "zh/on-call/integration/change-integration/github", + "zh/on-call/integration/change-integration/jenkins" ] }, { @@ -3174,7 +3175,8 @@ "group": "Change Integration", "pages": [ "en/on-call/integration/change-integration/custom-event", - "en/on-call/integration/change-integration/github" + "en/on-call/integration/change-integration/github", + "en/on-call/integration/change-integration/jenkins" ] }, { diff --git a/en/on-call/integration/change-integration/jenkins.mdx b/en/on-call/integration/change-integration/jenkins.mdx new file mode 100644 index 000000000..dd45984e8 --- /dev/null +++ b/en/on-call/integration/change-integration/jenkins.mdx @@ -0,0 +1,139 @@ +--- +title: "Jenkins change integration" +description: "Sync every build of your Jenkins deployment jobs to Flashduty On-call through the Jenkins Notification plugin, as change events you can correlate with alerts and incidents." +keywords: ["change integration", "Jenkins", "Notification plugin", "build", "deployment events"] +--- + +**Plan requirement**: This feature requires an On-call Standard or higher subscription. [Learn more](https://flashcat.cloud/flashduty/price/) + +Use the Jenkins [Notification plugin](https://plugins.jenkins.io/notification/) to sync job builds to Flashduty On-call. Each build becomes one Flashduty change; every phase of the build, from queued and started to finished, updates that same change. + +Jenkins cannot tell whether a build changed anything, so add the notification only to **jobs that deploy**, not to jobs that only compile or test. + +
+ +## In Flashduty On-call +--- + +1. In the Flashduty console, go to **Integration Center → Change Events** +2. Select **Jenkins** and enter an integration name +3. To assign changes to specific channels, add rules under the integration's **Routes** that match labels such as `job` +4. Click **Save** and copy the generated **Push URL** + +
+ +## Configure Jenkins +--- + + + + +Go to **Manage Jenkins → System** and make sure **Jenkins URL** under **Jenkins Location** is set to the address of your Jenkins. Without it, notifications carry no build link, Flashduty cannot identify the build, and the delivery is rejected. + + + + + +Go to **Manage Jenkins → Plugins → Available plugins**, search for **Notification**, and install it. You need Jenkins administrator permission. + + + + + +1. Open the deployment job, click **Configure**, find the **Job Notifications** section, and click **Add Endpoint** +2. **Format**: select `JSON` +3. **Protocol**: select `HTTP` +4. **Event**: select `All Events`, so Flashduty sees the whole build: queued, started, and finished +5. **URL Source**: select `Plain Text` and paste the complete Flashduty integration Push URL into **URL**. To keep the URL out of the job configuration, select `Credentials Store` instead, save the Push URL as a Secret text credential, and reference its ID +6. Keep **Branch** at the default `.*`, leave the other options at their defaults, and click **Save** + +If the job configuration is managed by a Jenkinsfile (for example, a multibranch pipeline), add the same settings to the Jenkinsfile's `properties`. You can generate the code on the pipeline's **Pipeline Syntax → Snippet Generator** page by selecting `properties: Set job properties`. + + + + + +Run the job once; the change appears in the Flashduty change list. The Notification plugin has no test button. If Jenkins cannot reach Flashduty, the build log shows `Failed to notify endpoint`; the plugin does not check the response, so a delivery that Flashduty rejects is not shown in Jenkins. + + + + +## What one change is +--- + +Each build is one change. Its change key (change_key) is `#`, for example `https://jenkins.example.com/job/deploy/18/#4711`. + +- Every phase of one build updates the same change +- Two builds of the same job are two changes +- When a job is deleted and recreated and its build numbers restart at 1, the queue IDs differ, so new builds are not merged into old ones +- When several Jenkins instances send to the same integration, their build URLs differ, so their builds are kept apart + +## Status mapping +--- + +| Build phase (phase) | Build result (status) | Flashduty change status | +|---|---|---| +| QUEUED | — | Ready | +| STARTED | — | Processing | +| COMPLETED, FINALIZED | SUCCESS | Done | +| COMPLETED, FINALIZED | UNSTABLE | Done | +| COMPLETED, FINALIZED | FAILURE | Failed | +| COMPLETED, FINALIZED | ABORTED, NOT_BUILT | Canceled | + +Done, Failed, and Canceled are end states; Flashduty records the change's end time when one arrives. COMPLETED means the build steps have finished; FINALIZED means post-build actions (such as archiving artifacts) have finished too. Both carry the same result. + +UNSTABLE means every build step ran, but tests or quality checks reported problems, so it is recorded as Done; use the `result` label to filter these changes. + +A `notifyEndpoints` step in a pipeline with `phase` set to `NONE` is accepted without creating a change. + +## Change content +--- + +| Field | Content | +|---|---| +| Title | ` #`, such as `platform/order-service/main #18` | +| Description | The endpoint's **Notes** option; empty when not set | +| Link | The build page | + +Labels can be used in routes and to filter the change list: + +| Label | Description | +|---|---| +| `job` | Full job name, including folders and the branch of a multibranch pipeline, such as `platform/order-service/main` | +| `build_number` | Build number | +| `branch` | The Git branch the build checked out | +| `commit` | The Git commit the build checked out | +| `phase` | The latest build phase | +| `result` | The build result, present once the build has finished | + +`branch` and `commit` appear only in notifications sent after the build checks out code, not in the queued and started phases. Route on `job`; otherwise the early and late events of one build can land in different channels. + +## FAQ +--- + + + + +- Make sure **Format** is `JSON` and **Protocol** is `HTTP` +- Make sure **Jenkins URL** is set under **Manage Jenkins → System** +- Look for `Notifying endpoint` or `Failed to notify endpoint` in the build log +- When **Branch** is not `.*`, only builds that have a `BRANCH_NAME` environment variable matching it send notifications + + + + + +The plugin sends one notification when the build completes (COMPLETED) and another when post-build actions finish (FINALIZED). Both carry the same result, so the change status does not change. To receive only one, set **Event** to `Job Finalized`, but then the queued and running phases are not shown. + + + + + +Flashduty rejects a delivery in these cases: + +- `build.full_url is missing`: the Jenkins URL is not configured +- `must use Format JSON`: the endpoint's **Format** is `XML` +- `unsupported build.phase` or `unsupported build.status`: Flashduty received a phase or result it does not support yet. Contact us + + + diff --git a/integration-docs/src/doc-map.mjs b/integration-docs/src/doc-map.mjs index e581768e1..b1f0e5b1c 100644 --- a/integration-docs/src/doc-map.mjs +++ b/integration-docs/src/doc-map.mjs @@ -101,6 +101,7 @@ export const docMap = { CustomChange: `${integrationBase}/change-integration/custom-event.mdx`, GithubChange: `${integrationBase}/change-integration/github.mdx`, + JenkinsChange: `${integrationBase}/change-integration/jenkins.mdx`, Jira: { zh: 'legacy/zh/jira-change.md', en: 'legacy/en/jira-change.md', diff --git a/zh/on-call/integration/change-integration/jenkins.mdx b/zh/on-call/integration/change-integration/jenkins.mdx new file mode 100644 index 000000000..55590324a --- /dev/null +++ b/zh/on-call/integration/change-integration/jenkins.mdx @@ -0,0 +1,139 @@ +--- +title: "Jenkins 变更集成" +description: "通过 Jenkins Notification 插件将部署任务的每次构建同步到 Flashduty On-call,作为变更事件与告警、故障关联。" +keywords: ["变更集成", "Jenkins", "Notification 插件", "构建", "部署事件"] +--- + +**版本要求**:此功能需要 On-call 标准版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/) + +通过 Jenkins 的 [Notification 插件](https://plugins.jenkins.io/notification/),将任务(Job)的构建同步到 Flashduty On-call。每一次构建对应一条 Flashduty 变更;构建从排队、开始执行到结束的每个阶段,都会更新同一条变更。 + +Jenkins 无法区分一次构建是否发布了变更,因此只需在**执行部署的任务**上配置通知,不要在单纯编译、测试的任务上配置。 + +
+ +## 在 Flashduty On-call +--- + +1. 进入 Flashduty 控制台,选择 **集成中心 → 变更事件** +2. 选择 **Jenkins**,填写集成名称 +3. 如需把变更分派到指定协作空间,在集成的 **路由** 中按标签(例如 `job`)配置规则 +4. 点击 **保存**,复制生成的 **推送地址** + +
+ +## 在 Jenkins 中配置 +--- + + + + +进入 **Manage Jenkins → System**,确认 **Jenkins Location** 中的 **Jenkins URL** 已填写为 Jenkins 的访问地址。未填写时推送内容不含构建链接,Flashduty 无法识别构建,会拒绝推送。 + + + + + +进入 **Manage Jenkins → Plugins → Available plugins**,搜索 **Notification** 并安装。需要 Jenkins 管理员权限。 + + + + + +1. 打开部署任务,点击 **Configure**,找到 **Job Notifications** 区域,点击 **Add Endpoint** +2. **Format**:选择 `JSON` +3. **Protocol**:选择 `HTTP` +4. **Event**:选择 `All Events`,Flashduty 才能看到排队、开始和结束的完整过程 +5. **URL Source**:选择 `Plain Text`,**URL** 粘贴 Flashduty 集成的完整推送地址。不希望在任务配置中明文显示地址时,可选择 `Credentials Store`,把推送地址保存为 Secret text 凭据后引用其 ID +6. **Branch** 保持默认的 `.*`,其余选项保持默认,点击 **Save** + +任务配置由 Jenkinsfile 管理(例如多分支流水线)时,在 Jenkinsfile 的 `properties` 中添加同样的配置,可通过流水线页面的 **Pipeline Syntax → Snippet Generator** 选择 `properties: Set job properties` 生成代码。 + + + + + +运行一次该任务,在 Flashduty 的变更列表中即可看到对应的变更。Notification 插件没有测试按钮。连接 Flashduty 失败时,构建日志中会出现 `Failed to notify endpoint`;插件不检查响应内容,Flashduty 拒绝的推送不会在 Jenkins 中显示。 + + + + +## 一条变更是什么 +--- + +每一次构建是一条变更,变更标识(change_key)为 `<构建完整地址>#<队列 ID>`,例如 `https://jenkins.example.com/job/deploy/18/#4711`。 + +- 同一次构建的所有阶段更新同一条变更 +- 同一任务的两次构建是两条变更 +- 任务被删除后重建、构建编号从 1 重新开始时,队列 ID 不同,不会与旧构建混为一条 +- 多个 Jenkins 实例推送到同一个集成时,构建地址不同,不会混淆 + +## 状态映射 +--- + +| 构建阶段(phase) | 构建结果(status) | Flashduty 变更状态 | +|---|---|---| +| QUEUED | — | Ready | +| STARTED | — | Processing | +| COMPLETED、FINALIZED | SUCCESS | Done | +| COMPLETED、FINALIZED | UNSTABLE | Done | +| COMPLETED、FINALIZED | FAILURE | Failed | +| COMPLETED、FINALIZED | ABORTED、NOT_BUILT | Canceled | + +Done、Failed 和 Canceled 是结束状态,Flashduty 会记录变更结束时间。COMPLETED 表示构建步骤执行完毕,FINALIZED 表示构建后操作(例如归档制品)也已完成,两者结果相同。 + +UNSTABLE 表示构建步骤全部执行完成,但测试或质量检查报告了问题,因此记为 Done;可以通过 `result` 标签筛选出这类变更。 + +在流水线中调用 `notifyEndpoints` 步骤且 `phase` 为 `NONE` 时,推送返回成功但不生成变更。 + +## 变更内容 +--- + +| 字段 | 内容 | +|---|---| +| 标题 | `<任务完整名称> #<构建编号>`,例如 `platform/order-service/main #18` | +| 描述 | 通知地址中 **Notes** 选项的内容,未填写时为空 | +| 链接 | 构建页面 | + +标签可用于路由和在变更列表中筛选: + +| 标签 | 说明 | +|---|---| +| `job` | 任务完整名称,包含文件夹和多分支流水线的分支,例如 `platform/order-service/main` | +| `build_number` | 构建编号 | +| `branch` | 构建检出的 Git 分支 | +| `commit` | 构建检出的 Git 提交 | +| `phase` | 最新的构建阶段 | +| `result` | 构建结果,结束后才有 | + +`branch` 和 `commit` 只在构建检出代码之后的推送中出现,排队和开始阶段没有。请按 `job` 配置路由规则,否则同一次构建的前后事件可能进入不同的协作空间。 + +## 常见问题 +--- + + + + +- 确认 **Format** 选择的是 `JSON`,**Protocol** 选择的是 `HTTP` +- 确认 **Manage Jenkins → System** 中已填写 **Jenkins URL** +- 查看构建日志中是否有 `Notifying endpoint` 或 `Failed to notify endpoint` +- **Branch** 不是 `.*` 时,只有带 `BRANCH_NAME` 环境变量且分支匹配的构建才会推送 + + + + + +插件在构建完成(COMPLETED)和构建后操作完成(FINALIZED)时各推送一次,两者结果相同,变更状态不变。只想接收一次时,可以把 **Event** 改为 `Job Finalized`,但这样就看不到排队和执行中的阶段。 + + + + + +Flashduty 在以下情况拒绝推送: + +- `build.full_url is missing`:Jenkins URL 未配置 +- `must use Format JSON`:通知地址的 **Format** 选择了 `XML` +- `unsupported build.phase` 或 `unsupported build.status`:收到了 Flashduty 尚未支持的阶段或结果,请联系我们 + + + From b1567f18e459c73e5e8a487aa01c133867dff4f2 Mon Sep 17 00:00:00 2001 From: ysyneu Date: Mon, 28 Sep 2026 10:00:26 -0700 Subject: [PATCH 16/36] docs(change): add Buildkite change integration page --- docs.json | 6 +- .../change-integration/buildkite.mdx | 123 ++++++++++++++++++ integration-docs/src/doc-map.mjs | 1 + .../change-integration/buildkite.mdx | 123 ++++++++++++++++++ 4 files changed, 251 insertions(+), 2 deletions(-) create mode 100644 en/on-call/integration/change-integration/buildkite.mdx create mode 100644 zh/on-call/integration/change-integration/buildkite.mdx diff --git a/docs.json b/docs.json index 0999fbc90..73d3e9f55 100644 --- a/docs.json +++ b/docs.json @@ -1779,7 +1779,8 @@ "zh/on-call/integration/change-integration/gitlab", "zh/on-call/integration/change-integration/hcp-terraform", "zh/on-call/integration/change-integration/argocd", - "zh/on-call/integration/change-integration/netlify" + "zh/on-call/integration/change-integration/netlify", + "zh/on-call/integration/change-integration/buildkite" ] }, { @@ -3182,7 +3183,8 @@ "en/on-call/integration/change-integration/gitlab", "en/on-call/integration/change-integration/hcp-terraform", "en/on-call/integration/change-integration/argocd", - "en/on-call/integration/change-integration/netlify" + "en/on-call/integration/change-integration/netlify", + "en/on-call/integration/change-integration/buildkite" ] }, { diff --git a/en/on-call/integration/change-integration/buildkite.mdx b/en/on-call/integration/change-integration/buildkite.mdx new file mode 100644 index 000000000..a44fd0b5e --- /dev/null +++ b/en/on-call/integration/change-integration/buildkite.mdx @@ -0,0 +1,123 @@ +--- +title: "Buildkite change integration" +description: "Sync Buildkite pipeline builds to Flashduty On-call through a Buildkite webhook, as change events you can correlate with alerts and incidents." +keywords: ["change integration", "Buildkite", "build", "deployment", "Webhook", "CI/CD"] +--- + +**Plan requirement**: This feature requires an On-call Standard or higher subscription. [Learn more](https://flashcat.cloud/flashduty/price/) + +Use a Buildkite organization's webhook notification service to sync pipeline builds to Flashduty On-call. Each build becomes one Flashduty change; every state of the build, from scheduled and running through failing to passed, failed, or canceled, updates that same change. + +We recommend sending only deployment pipelines: select those pipelines in the webhook, or use branch filtering to send builds of release branches only. + +
+ +## In Flashduty On-call +--- + +1. In the Flashduty console, go to **Integration Center → Change Events** +2. Select **Buildkite** and enter an integration name +3. To assign changes to specific channels, add rules under the integration's **Routes** that match labels such as `pipeline` or `ref` +4. Click **Save** and copy the generated **Push URL** + +
+ +## Configure Buildkite +--- + + + + +In your Buildkite organization, go to **Settings → Notification Services** and click **Add** next to **Webhook**. You need organization admin permission. + + + + + +1. **Description**: a name you can recognize, such as `Flashduty` +2. **Webhook URL**: paste the complete Flashduty integration Push URL +3. **Token**: keep the default; Flashduty authenticates with the `integration_key` in the Push URL + + + + + +1. Under **Events**, select `build.scheduled`, `build.running`, `build.failing`, `build.finished`, and `build.skipped` +2. Under **Pipelines**, choose the pipelines to send (all, specific pipelines, or the pipelines of specific teams or clusters) +3. To send only some branches, enter branch patterns under **Branch filtering**; leave it empty for all branches +4. Click **Add Webhook Notification** to save + + + + +## What one change is +--- + +One build is one change. Its change identifier (change_key) is the build's `build.id`, a UUID unique across Buildkite. Every `build.*` event of the same build updates the same change; two builds of the same pipeline and branch are two changes, and a rebuild creates a new build and a new change. + +## Status mapping +--- + +Flashduty takes the status from `build.state` in the delivery: + +| Buildkite build state | Flashduty change status | +|---|---| +| blocked (waiting on a block step) | Planned | +| creating, scheduled, waiting | Ready | +| running, failing, waiting_failed, canceling | Processing | +| passed | Done | +| failed | Failed | +| canceled, skipped, not_run | Canceled | + +Done, Failed, and Canceled are end states; Flashduty records the change's end time when one arrives. A build waiting on a block step is delivered as `build.finished` with state `passed` and `blocked` set to `true`; Flashduty records it as Planned and updates it to the final status when the build continues and finishes. + +These deliveries return success but create no change: `ping` and other non-build events such as `job.*`, `agent.*`, and `cluster_token.*`. + +## Change content +--- + +| Field | Content | +|---|---| +| Title | `: build # on ` | +| Description | The build message, usually the commit message | +| Link | The build's page in Buildkite | + +Use labels for routing and for filtering the change list: + +| Label | Description | +|---|---| +| `pipeline` | Pipeline slug | +| `repo` | The pipeline's repository URL | +| `ref` | The build's branch | +| `sha` | The build's commit SHA (absent until Buildkite resolves the commit) | +| `actor` | Name of the user who triggered the build | +| `source` | How the build was triggered: `webhook`, `api`, `ui`, `trigger_job`, or `schedule` | +| `build_id` | Build UUID | +| `build_number` | Build number within the pipeline | +| `state` | The latest Buildkite build state; `blocked` while waiting on a block step | + +## FAQ +--- + + + + +- Make sure the webhook has the `build.*` events selected; `job.*` or `agent.*` events alone create no changes +- Make sure the build's pipeline and branch are within the webhook's **Pipelines** and **Branch filtering** settings +- At the bottom of the webhook settings page, click **Load recent requests** to see the last 20 deliveries and Flashduty's responses + + + + + +No. An event with the same state and time is recorded only once. + + + + + +- `unsupported build.state`: Flashduty received a build state it does not support yet; contact us +- `build.id is missing`: the delivery is incomplete; make sure it comes from Buildkite's webhook notification service + + + diff --git a/integration-docs/src/doc-map.mjs b/integration-docs/src/doc-map.mjs index 46ebae482..ef4ad49c9 100644 --- a/integration-docs/src/doc-map.mjs +++ b/integration-docs/src/doc-map.mjs @@ -105,6 +105,7 @@ export const docMap = { HcpTerraformChange: `${integrationBase}/change-integration/hcp-terraform.mdx`, ArgocdChange: `${integrationBase}/change-integration/argocd.mdx`, NetlifyChange: `${integrationBase}/change-integration/netlify.mdx`, + BuildkiteChange: `${integrationBase}/change-integration/buildkite.mdx`, Jira: { zh: 'legacy/zh/jira-change.md', en: 'legacy/en/jira-change.md', diff --git a/zh/on-call/integration/change-integration/buildkite.mdx b/zh/on-call/integration/change-integration/buildkite.mdx new file mode 100644 index 000000000..85abb94b9 --- /dev/null +++ b/zh/on-call/integration/change-integration/buildkite.mdx @@ -0,0 +1,123 @@ +--- +title: "Buildkite 变更集成" +description: "通过 Buildkite Webhook 将流水线构建同步到 Flashduty On-call,作为变更事件与告警、故障关联。" +keywords: ["变更集成", "Buildkite", "构建", "部署", "Webhook", "CI/CD"] +--- + +**版本要求**:此功能需要 On-call 标准版及以上订阅。[了解更多](https://flashcat.cloud/flashduty/price/) + +通过 Buildkite 组织的 Webhook 通知服务,将流水线的构建(Build)同步到 Flashduty On-call。每一次构建对应一条 Flashduty 变更;构建从排队、运行、出现失败到通过、失败或取消的每个状态,都会更新同一条变更。 + +建议只为部署类流水线开启推送:在 Webhook 中选择对应的流水线,或用分支过滤只推送发布分支的构建。 + +
+ +## 在 Flashduty On-call +--- + +1. 进入 Flashduty 控制台,选择 **集成中心 → 变更事件** +2. 选择 **Buildkite**,填写集成名称 +3. 如需把变更分派到指定协作空间,在集成的 **路由** 中按标签(例如 `pipeline`、`ref`)配置规则 +4. 点击 **保存**,复制生成的 **推送地址** + +
+ +## 在 Buildkite 中配置 +--- + + + + +进入 Buildkite 组织的 **Settings → Notification Services**,在 **Webhook** 一栏点击 **Add**。需要组织管理员权限。 + + + + + +1. **Description**:填写便于识别的名称,例如 `Flashduty` +2. **Webhook URL**:粘贴 Flashduty 集成的完整推送地址 +3. **Token**:保持默认即可,Flashduty 通过推送地址中的 `integration_key` 鉴权 + + + + + +1. 在 **Events** 中勾选 `build.scheduled`、`build.running`、`build.failing`、`build.finished` 和 `build.skipped` +2. 在 **Pipelines** 中选择要推送的流水线(全部、指定流水线、指定团队或集群的流水线) +3. 如需只推送部分分支,在 **Branch filtering** 中填写分支规则,留空表示所有分支 +4. 点击 **Add Webhook Notification** 保存 + + + + +## 一条变更是什么 +--- + +一次构建是一条变更,变更标识(change_key)是构建的 `build.id`(Buildkite 平台内唯一的 UUID)。同一次构建的所有 `build.*` 事件更新同一条变更;同一流水线、同一分支的两次构建是两条变更,重新构建(Rebuild)也会产生新的构建和新的变更。 + +## 状态映射 +--- + +Flashduty 按推送内容中的 `build.state` 确定状态: + +| Buildkite 构建状态 | Flashduty 变更状态 | +|---|---| +| blocked(等待 block step 解除) | Planned | +| creating、scheduled、waiting | Ready | +| running、failing、waiting_failed、canceling | Processing | +| passed | Done | +| failed | Failed | +| canceled、skipped、not_run | Canceled | + +Done、Failed 和 Canceled 是结束状态,Flashduty 会记录变更结束时间。等待 block step 的构建以 `build.finished` 推送,状态为 `passed` 且 `blocked` 为 `true`,Flashduty 将其记为 Planned,构建继续运行并结束后更新为最终状态。 + +以下推送返回成功但不生成变更:`ping`、`job.*`、`agent.*`、`cluster_token.*` 等非构建事件。 + +## 变更内容 +--- + +| 字段 | 内容 | +|---|---| +| 标题 | `<流水线名称>: build #<构建号> on <分支>` | +| 描述 | 构建的 message,通常是提交信息 | +| 链接 | Buildkite 中该构建的页面 | + +标签可用于路由和在变更列表中筛选: + +| 标签 | 说明 | +|---|---| +| `pipeline` | 流水线 slug | +| `repo` | 流水线的代码仓库地址 | +| `ref` | 构建的分支 | +| `sha` | 构建的提交 SHA(构建尚未解析出提交时不带此标签) | +| `actor` | 触发构建的用户名称 | +| `source` | 构建触发方式:`webhook`、`api`、`ui`、`trigger_job`、`schedule` | +| `build_id` | 构建 UUID | +| `build_number` | 流水线内的构建号 | +| `state` | 最新的 Buildkite 构建状态,等待 block step 时为 `blocked` | + +## 常见问题 +--- + + + + +- 确认 Webhook 勾选了 `build.*` 事件,只勾选 `job.*` 或 `agent.*` 事件不会产生变更 +- 确认构建所在的流水线和分支在 Webhook 的 **Pipelines** 和 **Branch filtering** 范围内 +- 在 Webhook 设置页底部点击 **Load recent requests**,查看最近 20 次推送和 Flashduty 的响应 + + + + + +不会。同一状态、同一时间的事件只记录一次。 + + + + + +- `unsupported build.state`:收到了 Flashduty 尚未支持的构建状态,请联系我们 +- `build.id is missing`:推送内容不完整,请确认推送来自 Buildkite 的 Webhook 通知服务 + + + From 0c2653c8037dd7807959e72b73225fc24b82d0dc Mon Sep 17 00:00:00 2001 From: ysyneu Date: Mon, 28 Sep 2026 10:05:32 -0700 Subject: [PATCH 17/36] docs(change): list every Jenkins rejection reason --- en/on-call/integration/change-integration/jenkins.mdx | 2 ++ zh/on-call/integration/change-integration/jenkins.mdx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/en/on-call/integration/change-integration/jenkins.mdx b/en/on-call/integration/change-integration/jenkins.mdx index dd45984e8..89cdd5b9c 100644 --- a/en/on-call/integration/change-integration/jenkins.mdx +++ b/en/on-call/integration/change-integration/jenkins.mdx @@ -132,6 +132,8 @@ The plugin sends one notification when the build completes (COMPLETED) and anoth Flashduty rejects a delivery in these cases: - `build.full_url is missing`: the Jenkins URL is not configured +- `build.queue_id is missing`: the payload has no queue ID. Make sure the delivery comes from the Notification plugin +- `build.status is missing`: an end phase arrived without a build result, usually from a pipeline calling `notifyEndpoints(phase: 'COMPLETED')` or `'FINALIZED'` before the result is set - `must use Format JSON`: the endpoint's **Format** is `XML` - `unsupported build.phase` or `unsupported build.status`: Flashduty received a phase or result it does not support yet. Contact us diff --git a/zh/on-call/integration/change-integration/jenkins.mdx b/zh/on-call/integration/change-integration/jenkins.mdx index 55590324a..93d1e641d 100644 --- a/zh/on-call/integration/change-integration/jenkins.mdx +++ b/zh/on-call/integration/change-integration/jenkins.mdx @@ -132,6 +132,8 @@ UNSTABLE 表示构建步骤全部执行完成,但测试或质量检查报告 Flashduty 在以下情况拒绝推送: - `build.full_url is missing`:Jenkins URL 未配置 +- `build.queue_id is missing`:推送内容缺少队列 ID,请确认推送来自 Notification 插件 +- `build.status is missing`:结束阶段没有构建结果,通常是在流水线中构建结果确定之前调用了 `notifyEndpoints(phase: 'COMPLETED')` 或 `'FINALIZED'` - `must use Format JSON`:通知地址的 **Format** 选择了 `XML` - `unsupported build.phase` 或 `unsupported build.status`:收到了 Flashduty 尚未支持的阶段或结果,请联系我们 From b8816937f2ae2815f5867838cb759782d88a15ba Mon Sep 17 00:00:00 2001 From: Fiona Date: Mon, 28 Sep 2026 21:15:59 -0700 Subject: [PATCH 18/36] docs(rum): document on-error capture for Web SDK 0.3.0 --- en/rum/best-practices/sampling.mdx | 6 +++- en/rum/quickstart/app-management.mdx | 4 +++ en/rum/quickstart/faq.mdx | 2 +- en/rum/sdk/web/advanced-config.mdx | 47 ++++++++++++++++++++++++++-- en/rum/sdk/web/faq.mdx | 2 +- en/rum/sdk/web/sdk-integration.mdx | 4 +-- zh/rum/best-practices/sampling.mdx | 6 +++- zh/rum/quickstart/app-management.mdx | 4 +++ zh/rum/sdk/web/advanced-config.mdx | 47 ++++++++++++++++++++++++++-- zh/rum/sdk/web/faq.mdx | 2 +- zh/rum/sdk/web/sdk-integration.mdx | 4 +-- 11 files changed, 113 insertions(+), 15 deletions(-) diff --git a/en/rum/best-practices/sampling.mdx b/en/rum/best-practices/sampling.mdx index b29468e21..094ad3855 100644 --- a/en/rum/best-practices/sampling.mdx +++ b/en/rum/best-practices/sampling.mdx @@ -309,7 +309,11 @@ The base rule uses `hash(userId) % 100` instead of `Math.random()`, which brings ## Best practice 3: full error capture with proportional sampling for the rest -A common requirement is "cut data volume to 20%, but never miss an error". Setting `sessionSampleRate` to 20 will not do it: sampling works per session, and a session that loses the draw reports nothing at all — errors included (rule 1). You would lose roughly four fifths of your errors along with the volume. The correct shape is to collect every session so no error is lost, then bucket on a stable key inside `beforeSend` so only the winning share keeps full data: + +Starting with Web SDK **0.3.0**, enable `sessionOnError` (and `sessionReplayOnError` if you need error replays) to capture error sessions without writing your own `beforeSend`; see [on-error session capture](/en/rum/sdk/web/advanced-config#on-error-session-capture) for configuration, billing, and limitations. The recipe below remains available for older versions or custom event filtering. Its failed-request filtering differs from the new options: a failed resource event alone does not trigger on-error capture. + + +A common requirement is "cut data volume to 20%, but never miss an error". Setting `sessionSampleRate` to 20 will not do it: sampling works per session, and a session that loses the draw reports nothing at all — errors included (rule 1). You would lose roughly four fifths of your errors along with the volume. The custom filtering recipe below collects every session so no error is lost, then buckets on a stable key inside `beforeSend` so only the winning share keeps full data: - **Error events**: always kept — 100% of errors - **Failed requests**: always kept — 100% of API failures (HTTP 5xx and request failures are resource events, not error events) diff --git a/en/rum/quickstart/app-management.mdx b/en/rum/quickstart/app-management.mdx index ca7a20b6c..d9f99b94a 100644 --- a/en/rum/quickstart/app-management.mdx +++ b/en/rum/quickstart/app-management.mdx @@ -307,10 +307,14 @@ The **Remote Configuration** tab lets you adjust collection and privacy paramete |------|------|------| | **Session sample rate** | Integer 0–100 (%) | Percentage of sessions collected. Leave it empty to skip delivering this field; clients keep the value set at SDK initialization | | **Session replay sample rate** | Integer 0–100 (%) | Percentage of sessions recorded by Session Replay. If empty, the SDK setting applies | +| **On-error session capture** (`sessionOnError`) | On / Off / Use SDK setting | For sessions missed by session sampling, uploads up to the last minute of events on error and continues collection; requires Web SDK 0.3.0 or later | +| **On-error replay capture** (`sessionReplayOnError`) | On / Off / Use SDK setting | For collected sessions missed by replay sampling, uploads buffered replay on error and continues recording; requires Web SDK 0.3.0 or later | | **Trace sample rate** | Integer 0–100 (%) | A second session-level sampling pass within already-collected sessions, deciding which sessions inject trace headers into eligible requests; the outcome is consistent within one session. Overall trace coverage is roughly *session sample rate × trace sample rate*. If empty, the SDK setting applies | | **Replay privacy level** | `mask` / `mask-user-input` / `allow` | Default masking of page content in Session Replay: `mask` obscures text and hides input values; `mask-user-input` keeps page text and hides only what users typed; `allow` records the page as it is. Loosening the level starts collecting content that was not collected before, and replays already uploaded cannot be retroactively masked. The console asks you to confirm again before publishing | | **Custom configuration keys** | Key–value pairs typed as string / number / boolean / JSON | Delivered to clients together with the remote configuration and read by your application code; the platform does not interpret them. Up to 5 keys; each key name is at most 64 bytes (counted in UTF-8, not characters), each value at most 4 KB and nesting at most 3 levels (objects and arrays each count one level), and all custom entries together at most 16 KB | +The two on-error options are independent: **On** delivers `true`, **Off** delivers `false`, and **Use SDK setting** omits the field so the corresponding `init()` option applies (off if unset). Browser applications require Web SDK 0.3.0 or later with `remoteConfigurationEnabled: true` at initialization. Turning off on-error capture does not affect sessions selected by ordinary sampling. See [Web SDK on-error session capture](/en/rum/sdk/web/advanced-config#on-error-session-capture) for scope, billing, and limitations. + iOS, Android, and WeChat Mini Program applications also show the **Remote Configuration** tab, but their SDKs read only the **session sample rate** and **custom configuration keys** (none of the three has Session Replay; the other values are neither delivered nor effective). Every SDK has to opt in with `remoteConfigurationEnabled: true` at initialization (off by default; an application that has not opted in never requests the configuration). On iOS this requires SDK 0.6.0 or later, see [iOS SDK Advanced Configuration](/en/rum/sdk/ios/advanced-config#remote-configuration); on Android it requires SDK 0.7.0 or later, see [Android SDK Advanced Configuration](/en/rum/sdk/android/advanced-config#remote-configuration-adjust-the-sample-rate-from-the-console). diff --git a/en/rum/quickstart/faq.mdx b/en/rum/quickstart/faq.mdx index 52b1b2784..97eda8032 100644 --- a/en/rum/quickstart/faq.mdx +++ b/en/rum/quickstart/faq.mdx @@ -20,7 +20,7 @@ Confirm that the RUM SDK is correctly imported: ```html CDN Integration