diff --git a/en/ai-sre/sessions.mdx b/en/ai-sre/sessions.mdx index bd25fe01..9a33a94e 100644 --- a/en/ai-sre/sessions.mdx +++ b/en/ai-sre/sessions.mdx @@ -67,7 +67,7 @@ A new session gets an automatic title after its first turn; you can rename it at | Indicator | Meaning | |---|---| -| Spinning circle | The agent is running | +| Spinning circle | The agent is running: either the current turn is executing, or a dispatched subagent is still running | | 🔭 + number | Number of background tasks running — see [Task Panel and Background Tasks](#task-panel-and-background-tasks) | | Blue dot | New content you have not seen; cleared when you open the session | | Relative time | Last activity (for example, `5m`, `3h`) | @@ -112,7 +112,9 @@ While a turn runs, the Send button becomes a **Stop** button. Stopping interrupt ### Queueing messages while running -You can keep sending messages while a turn runs; they queue and run in order after the current turn. Queued messages appear above the input, where you can edit, remove or **Clear all** of them. Once the agent has started on a message it can no longer be withdrawn; use Stop to interrupt. +**While the current turn is executing**, you can keep sending messages; they queue and run in order after the current turn. Queued messages appear above the input, where you can edit, remove or **Clear all** of them. Once the agent has started on a message it can no longer be withdrawn; use Stop to interrupt. + +**Once the agent has handed the work to a subagent and its own turn has ended**, the session still counts as running (the list still shows the spinning circle, and the button beside the input is still Stop), but the main agent is idle: a message you send then does **not** queue, it starts a new turn immediately. The same holds after a page refresh, so the session is never mistaken for "executing" and your messages are not held back. ### Environment initialization @@ -150,13 +152,24 @@ If you send a new message instead of answering, the question is treated as skipp Some console pages **declare that AI can operate them**: each turn sends the agent the actions available on the page you are viewing, so on these pages the agent can read and fill in the form directly instead of only giving written advice. -Currently this covers the **Alert grouping** and **Flapping detection** pages under a channel's Noise reduction; see [Noise reduction](/en/on-call/channel/noise-reduction). Other pages have no page actions, so the agent cannot operate them. Page actions exist only in console sessions, not in IM, API, or automation sessions. +The console pages that declare page actions: + +| Page | What the agent can do | +|---|---| +| The **Alert grouping** and **Flapping detection** pages under a channel's Noise reduction (see [Noise reduction](/en/on-call/channel/noise-reduction)) | Read the form and fill in fields; actions that take effect immediately, such as **Save**, are confirmed one at a time | +| The **RUM Explorer** (see [Query and analyze with AI SRE](/en/rum/explorer/data-query#query-and-analyze-with-ai-sre)) | Look up field values, rewrite the query and event type, move the time range, set up the analytics chart; writes land straight on the page and are reverted with **Undo change** | + +Other pages have no page actions, so the agent can only give written advice. Page actions exist only in console sessions, not in IM, API, or automation sessions. + +Actions on the **Alert grouping** and **Flapping detection** pages work like this: - **Reading** the form (fields, current values, options, whether writable) needs no authorization. - **Filling** a field only writes the value into the form; it does not submit. Review it and click **Save** yourself. - **Saving**, and other actions that take effect immediately, each pop up their own confirmation card in the conversation (above the input), listing "old value → new value" with **Cancel** and the action's own verb (such as **Save**). -Before touching the page, the agent asks with a question card how to apply the change: fill the form for you to review and save, or save directly. While it works, the page gets a brand-colored highlight and an **AI is working on this page** bar at the top, which changes to **Done** when finished; you can click **Stop** to interrupt. Sending a new message or leaving the session voids any unanswered confirmation card. In a shared session opened read-only, page actions do not run. +Before touching either of those pages, the agent asks with a question card how to apply the change: fill the form for you to review and save, or save directly. While it works, the page gets a brand-colored highlight and an **AI is working on this page** bar at the top, which changes to **Done** when finished; you can click **Stop** to interrupt. Sending a new message or leaving the session voids any unanswered confirmation card. In a shared session opened read-only, page actions do not run. + +Writes on the **RUM Explorer** raise no confirmation card: the agent rewrites the query box, the event type, the time range and the analytics chart, and runs them right away. The AI SRE bar under the query box reports progress and the result (**Filling in the query**, **Querying**, then the number of events found, **Query complete**, or **Query complete, no data**). To get back the page you had before the write, click **Undo change** on that bar. Looking up which values a field holds does not change the page. ### When authorization is required @@ -319,6 +332,17 @@ The **reply language** is set when the session is created and used for the whole This section is for developers integrating AI SRE sessions through the [Open API](/en/api-reference/ai-sre/sessions/session-read-info). +### Session run state + +Both `POST /safari/session/get` and `POST /safari/session/list` return two run-state fields, and they mean different things: + +| Field | Meaning | +|---|---| +| `is_running` | The session holds a running state: the current turn is executing, **or** a dispatched subagent's round has not ended. Running background commands and monitors do not count | +| `turn_in_flight` | Whether the current turn is actually executing | + +After the agent hands work to a subagent, its own turn ends first: during that window `is_running` stays `true` while `turn_in_flight` is `false`. Read `turn_in_flight` to know whether a message sent now will queue, and `is_running` to know whether the session is still working. Both are computed in the response, so they describe the moment you query. + ### Withdrawing a queued message The `pending_messages` field in the `POST /safari/session/get` response lists queued messages the agent has not read yet, in execution order. Before the agent reads one, its author can withdraw it with `POST /safari/session/message/cancel`, passing `session_id` and `invocation_id` (the invocation ID returned when the message was sent). The `result` field means: diff --git a/en/changelog/changelog.mdx b/en/changelog/changelog.mdx index 00b92192..3a0c50da 100644 --- a/en/changelog/changelog.mdx +++ b/en/changelog/changelog.mdx @@ -4,6 +4,22 @@ description: "This page documents important updates and feature releases for Fla keywords: ["Changelog", "Product Release", "Feature Updates", "Flashduty", "Version History"] --- + + +### RUM Explorer: query and analyze with AI SRE + +The sparkle at the left of the query box opens AI SRE now — on an account with AI SRE enabled, for a member who may chat in it; ⌘ + Enter in normal query mode does the same, Ctrl + Enter on Windows and Linux. Say in one sentence what you are looking for and AI SRE writes it into the page: the box's conditions, the event type, the time range, and the chart in analytics, then runs the query itself. The status bar under the query box reports the turn — filling in the query, querying (counting seconds past 3), N found, query complete, no data, query failed, stopped; **Undo change** puts the page back the way it was before the write, and works only while the box still holds what AI SRE wrote. **Stop** ends a running turn; clicking the status bar or pressing Esc only folds the conversation without ending it, leaving the results in view. An account without AI SRE, or one out of AI SRE credits, keeps the basic natural-language query at the same entry: a sentence becomes DQL, previewed before you apply it. See [Data query syntax guide](/en/rum/explorer/data-query). + +### RUM dashboards: a dashboard belongs to one application + +A custom dashboard now belongs to the application it was created in, and every panel's query reads that application only, so the panel editor drops its application picker: the old **Page application** option (`$app`, resolved to the page's current application) survives only in definitions saved before this change. The Insights tab bar lists the current application's dashboards (by title, up to 100) and **Manage dashboards** lists every application's; opening another application's dashboard from the manage page or a link first switches the page to the application it belongs to, then opens it. Switching the application by hand on a dashboard tab leaves that dashboard and returns to the **Overview** tab, which belongs to the new application. A copy of another application's dashboard stays in that application. Dashboards saved before this change take the application of their first query that reads a concrete one; an old dashboard that reads no concrete application no longer appears in the application's tabs and can no longer be edited, so create it again under its application. See [RUM custom dashboards](/en/rum/analytics/custom-dashboards). + +### RUM errors split by where they were raised + +The same error message raised from two different places in the code now makes two Issues instead of one. The location is taken from what survives a rebuild: for a Web JS error, the script and function of its top meaningful stack frame; for Android, the throw site of the exception chain's root cause plus the first app-code frame below it; for an iOS crash, the crash site plus the first app-code frame below it — line and column numbers, build hashes and minified or obfuscated names take no part, so a new release does not split one bug into new Issues. A minified frame that cannot be told apart is not used as a location, and such errors keep grouping by type and message. An iOS frame the SDK could not resolve can only be told apart by its offset inside the image, and that offset is stable within one build only, so such a crash can become a new Issue after every release — uploading dSYMs changes how the stack reads in the console, not how it is grouped. Existing browser and Android Issues keep receiving their message from every location, with their status, assignee and history; iOS crashes do not carry over to the old signal-only Issue and start anew by crash location. A custom fingerprint still takes precedence. See [Error grouping](/en/rum/error-tracking/error-aggregation). + + + ### Routing rules in a table or card view @@ -20,7 +36,7 @@ The people who can edit an MCP server or an A2A agent are not necessarily the pe ### RUM custom dashboards: build your own under Insights -The Insights tab bar no longer holds only the built-in dashboards: the **+** menu at its right end offers **New dashboard** (requires the **Dashboards Manage** permission) and **Manage dashboards**, and a custom dashboard opens as an extra tab (up to 100 tabs are listed); **Save to dashboard** on an analytics chart also turns the current question into one full-width panel. A panel asks the same aggregation question as the explorer — application (or the built-in `$app` variable, which follows the page's current application), event type, aggregation and field, group by and top N, plus a DQL filter — and draws as a time series, table, stat or text panel. Dashboard variables come in field-value and custom kinds, referenced in a panel's DQL as `${name}`, and a new dashboard starts with `env` / `service` / `version` field variables. Every save leaves a revision (the last 20 are kept), and a deleted dashboard goes to the trash for 30 days and can be restored from the manage page. See [RUM custom dashboards](/en/rum/analytics/custom-dashboards). +The Insights tab bar no longer holds only the built-in dashboards: the **+** menu at its right end offers **New dashboard** (requires the **Dashboards Manage** permission) and **Manage dashboards**, and a custom dashboard opens as an extra tab (up to 100 tabs are listed); **Save to dashboard** on an analytics chart also turns the current question into one full-width panel. A panel asks the same aggregation question as the explorer — event type, aggregation and field, group by and top N, plus a DQL filter (since 2026-10-25 a dashboard belongs to one application and its panels always read that application) — and draws as a time series, table, stat or text panel. Dashboard variables come in field-value and custom kinds, referenced in a panel's DQL as `${name}`, and a new dashboard starts with `env` / `service` / `version` field variables. Every save leaves a revision (the last 20 are kept), and a deleted dashboard goes to the trash for 30 days and can be restored from the manage page. See [RUM custom dashboards](/en/rum/analytics/custom-dashboards). ### A redesigned template detail page, with send test diff --git a/en/developer/cli.mdx b/en/developer/cli.mdx index a6552521..00607e8f 100644 --- a/en/developer/cli.mdx +++ b/en/developer/cli.mdx @@ -763,12 +763,16 @@ Common `create` flags: | `--disabled` | Create the rule disabled (enabled by default) | | `--schedule-enabled` | Whether the schedule trigger is enabled (default `true`) | | `--http-post-trigger` | Create and enable an HTTP POST trigger; when passed alone without any schedule flags, the CLI writes a placeholder cron and disables the schedule trigger | +| `--war-room-trigger` | Create and enable the war room creation trigger; requires `--war-room-channel-ids` and `--war-room-severities` together, and errors if either is missing. When passed alone without any schedule flags, the CLI likewise writes a placeholder cron and disables the schedule trigger (same as `--http-post-trigger`); passed together with `--schedule` and the other schedule flags, the schedule trigger stays enabled | +| `--war-room-channel-ids` / `--war-room-severities` | Match conditions for the war room trigger: the channel (collaboration space) IDs to watch (comma-separated, at least one) and the severities (`Critical`, `Warning`, `Info`; comma-separated, at least one). Both must be given together when the trigger is created | | `--prompt` / `--prompt-file` | Task prompt, exactly one required; `--prompt-file` reads from a file (`-` for stdin) | | `--environment-kind` / `--environment-id` | Runtime environment: `cloud` or `byoc` (`byoc` requires `--environment-id`); empty means automatic | When you create a rule from an IM conversation, omitting `--run-in` lets the server bind the rule to that conversation and inherit its scope; you neither need to nor should pass a chat, platform, integration, or session ID — the server resolves and authorizes the current conversation. Once bound to a conversation, every ordinary run starts a fresh execution session and, where the IM integration creates threads, a fresh IM thread, and it stays on the conversation and immutable scope captured at creation rather than reusing an old session or thread; a retry of the same run reuses that run's execution identity. If the bound conversation's scope no longer matches the rule when it runs, the run is skipped — the rule is never moved or run in another conversation. War-room Automations keep their existing behavior. Because each run starts from a fresh context, write the prompt so it carries the chat context it needs (the service, the team, the delivery target) and do not refer to "above" or to an earlier session. Like the scope, the execution destination is immutable after creation. -`update` accepts `--name`, `--prompt`/`--prompt-file`, `--schedule`/`--at`/`--weekday`/`--cron-expr`/`--timezone`, `--enable`/`--disable`, `--enable-schedule`/`--disable-schedule`, `--enable-http-post-trigger`/`--disable-http-post-trigger`, `--rotate-http-post-token`, and `--environment-kind`/`--environment-id`. The personal/team scope and the execution destination (`--run-in`) are both immutable after creation, so `update` exposes neither. `update`'s `--cron-expr` carries the same constraint as `create`: the minute must be a fixed `0`–`59` integer, so the fastest schedule is hourly, and minute wildcards, ranges, lists, and steps are unsupported. +The war room creation trigger starts a run whenever a war room (IM group chat) is created in one of the matching channels. That run's session lives in the war room's group chat, not in the console — `--run-in` does not apply to it, and it uses the execution environment already chosen in that group chat, so the rule's own environment does not affect it. Field semantics and run behaviour: [Automations · War room created](/en/ai-sre/automations#war-room-created). + +`update` accepts `--name`, `--prompt`/`--prompt-file`, `--schedule`/`--at`/`--weekday`/`--cron-expr`/`--timezone`, `--enable`/`--disable`, `--enable-schedule`/`--disable-schedule`, `--enable-http-post-trigger`/`--disable-http-post-trigger`, `--rotate-http-post-token`, `--enable-war-room-trigger`/`--disable-war-room-trigger`, `--war-room-channel-ids`/`--war-room-severities`, and `--environment-kind`/`--environment-id`. `--enable-war-room-trigger` and `--disable-war-room-trigger` are mutually exclusive and error if both are passed; `--war-room-channel-ids`/`--war-room-severities` replace the trigger's filters wholesale when passed, and the server requires both lists when `update` first creates the war room trigger. The personal/team scope and the execution destination (`--run-in`) are both immutable after creation, so `update` exposes neither. `update`'s `--cron-expr` carries the same constraint as `create`: the minute must be a fixed `0`–`59` integer, so the fastest schedule is hourly, and minute wildcards, ranges, lists, and steps are unsupported. `runs` supports `--status` (`queued`/`running`/`retrying`/`succeeded`/`partial`/`failed`/`skipped`/`abandoned`), `--trigger-kind` (server-side values `schedule`/`debug`/`manual`/`http_post`/`oncall_incident`/`war_room_created`, where `war_room_created` is a run triggered by a war room being created), `--since`/`--until`, `--page`, and `--limit`. `fire` authenticates with the trigger's token (`--token`, or the `FLASHDUTY_AUTOMATION_TRIGGER_TOKEN` environment variable); `--text` passes context for the run, and `--data` passes a full JSON request body (inline JSON or `-` to read stdin). diff --git a/en/developer/go-sdk.mdx b/en/developer/go-sdk.mdx index 2a943b9c..8d257edf 100644 --- a/en/developer/go-sdk.mdx +++ b/en/developer/go-sdk.mdx @@ -206,6 +206,15 @@ The following services have behavior that needs extra explanation: - `AutomationRuleCreateRequest.TeamID` (`team_id`) is a `*int64`: an explicit `0` means personal scope and a value greater than 0 picks a team in the account. Omitted, it inherits the authenticated IM conversation's scope when one is present; otherwise the server applies its normal default. A `current-chat` rule's scope must match that conversation's scope. - `AutomationRuleUpdateRequest` no longer has `TeamID` (nor `RunIn`): scope and execution destination are immutable after creation. Old code that set `TeamID` on an update request should drop the line — otherwise it will not compile. +The war room creation trigger's fields behave differently on the two request types: + +- On the create request they are plain values: `AutomationRuleCreateRequest.WarRoomTriggerEnabled` (`bool`), `WarRoomChannelIDs` (`[]int64`), `WarRoomSeverities` (`[]string`). On the update request all three are pointers (`*bool` / `*[]int64` / `*[]string`): nil leaves the field unchanged, a non-nil value is sent. +- The server creates the trigger when it is given one: `WarRoomTriggerEnabled` is true, or `WarRoomChannelIDs` is non-empty. In that case both the channel list and the severity list (`Critical` / `Warning` / `Info`) must be non-empty, and a missing one is rejected as an invalid parameter; severities alone do not create a trigger. +- Passing an empty slice on update is the same as omitting it: the server treats an empty list as not provided and keeps the stored value, so filters can only be replaced wholesale with non-empty lists — an empty array does not clear them. +- On the way back, `AutomationRuleItem.WarRoomTriggerEnabled` always has a value (false when there is no such trigger), while `WarRoomTriggerID`, `WarRoomChannelIDs`, and `WarRoomSeverities` are empty (`""` / empty slices). + +For what the fields mean and when the trigger fires, see [Automations · War room created](/en/ai-sre/automations#war-room-created). + ### Rule folders `client.RuleFolders` covers the six operations under `/monit/folder/*`. `ReadList` (`POST /monit/folder/list`) and `ReadHealth` (`POST /monit/folder/health`) take no request body. The first returns a flat `[]FolderItem` that you rebuild into a tree in the client from `ParentID` / `ParentPath` (dashboards and alert rules share that same tree); the second returns a `FolderHealthOutput`, whose `FolderHealthItem.HasIssue` marks a folder that — or whose visible descendant — has active alerts or rule runtime issues. On the write side `WriteCreate` (`/monit/folder/create`) and `WriteUpdate` (`/monit/folder/update`) return the `FolderItem`, while `WriteMove` (`/monit/folder/move`) and `WriteDelete` (`/monit/folder/delete`) return only a `*Response`. Further exported types are `FolderCreateRequest`, `FolderUpdateRequest`, `FolderMoveRequest`, and `FolderDeleteRequest`. @@ -245,7 +254,7 @@ out, _, err := client.DataSources.ToolsInvoke(ctx, req) ### Prometheus label values -`client.DataSources.ReadPrometheusLabelValues(ctx, dataSourceID, labelName)` (`GET /monit/prometheus/api/v1/label/{label_name}/values`, `monit-prometheus-read-label-values`) lists every value of one label on a Prometheus-compatible data source through the monitoring proxy: the label name goes in the URL path (the SDK escapes it), and the target data source is selected by the `X-DSID` request header — the SDK sets it from the `dataSourceID` argument (a `0` ID or an empty `labelName` errors immediately), with the ID taken from `/monit/datasource/list` and required to be a Prometheus-compatible data source of the current account. It is the only method whose success body is not the Flashduty `{request_id, data}` envelope: the response decodes straight into `PrometheusLabelValuesResponse` (`data` carries the label-value strings when `status` is `success`; `errorType` and `error` are present when it is `error`). Failures before the data source is reached (missing or invalid `X-DSID`, no such data source, or not a Prometheus type) return `text/plain`. The data source's own failures use its JSON error shape. The SDK treats both the same and puts the raw body in `*ErrorResponse.Message`. Supported deployments require monit-edge v0.35.0 or later. +`client.DataSources.ReadPrometheusLabelValues(ctx, dataSourceID, labelName)` (`GET /monit/prometheus/api/v1/label/{label_name}/values`, `monit-prometheus-read-label-values`) lists every value of one label on a Prometheus-compatible data source through the monitoring proxy: the label name goes in the URL path (the SDK escapes it), and the target data source is selected by the `X-DSID` request header — the SDK sets it from the `dataSourceID` argument (a `0` ID or an empty `labelName` errors immediately), with the ID taken from `/monit/datasource/list` and required to be a Prometheus-compatible data source of the current account. It is the only method whose success body is not the Flashduty `{request_id, data}` envelope: the response decodes straight into `PrometheusLabelValuesResponse` (`data` carries the label-value strings when `status` is `success`; `errorType` and `error` are present when it is `error`). Failures before the data source is reached (invalid `X-DSID`, no such data source, or not a Prometheus type) return `text/plain`. The data source's own failures use its JSON error shape. The SDK treats both the same and puts the raw body in `*ErrorResponse.Message`. Two cases return no error: a request that carries no `X-DSID`, and a data source whose monit-edge cluster has an instance older than v0.35.0 (one that does not support the resource proxy) — both answer 200 with an empty Prometheus-compatible body, where `data` is an empty array for `/api/v1/labels`, `/api/v1/series`, and `/api/v1/label/{label_name}/values`, and an empty object for `/api/v1/metadata`. So when you read an empty result, do not take it to mean the label has no values — first check that `X-DSID` was sent and whether the edge needs an upgrade. Supported deployments require monit-edge v0.35.0 or later. ### Data source configuration diff --git a/en/on-call/comparison/vs-pagerduty.mdx b/en/on-call/comparison/vs-pagerduty.mdx index d38a4824..19130208 100644 --- a/en/on-call/comparison/vs-pagerduty.mdx +++ b/en/on-call/comparison/vs-pagerduty.mdx @@ -98,7 +98,7 @@ Response solves "closing the loop quickly once the right person is found": a sin | **Reopen Incident** | Reopen after closure and notify | ✅ **Flashduty exclusive** | | **[Custom Fields](/en/on-call/configuration/custom-fields)** | Freely define incident business attributes (mark false positives, add meeting links, and so on), **with field-based search** | Both support; PagerDuty requires configuring Incident Types first and enabling fields one by one | | **[Custom Forms](/en/on-call/configuration/custom-forms)** | Conditionally show supplementary-info forms when creating, acknowledging, or closing an incident | Flashduty supports this across the full lifecycle; PagerDuty only supports required fields at closure (Enterprise tier only) | -| **Search Capability** | Search by labels, custom fields, title, personnel | Flashduty supports exact, wildcard, and regex matching; PagerDuty supports basic field-filter search | +| **Search Capability** | Search by labels, custom fields, title, personnel | Flashduty matches the alert title as a substring, wildcard, or regex, matches labels and custom fields exactly, and filters personnel by exact member; PagerDuty supports basic field-filter search | ### Status pages diff --git a/en/on-call/incident/alert-management.mdx b/en/on-call/incident/alert-management.mdx index 0e58a6ac..74f8d82f 100644 --- a/en/on-call/incident/alert-management.mdx +++ b/en/on-call/incident/alert-management.mdx @@ -43,7 +43,7 @@ The following filters are available at the top of the alert list: | Filter | Description | | :--- | :--- | -| **Alert Title** | Fuzzy match on the title | +| **Alert Title** | Substring match on the title, in plain text, wildcard, or regex form (see below) | | **Severity** | Multi-select Critical / Warning / Info | | **Channel** | Filter by the channel the alert belongs to | | **Integration** | Filter by the source integration of the alert | @@ -53,6 +53,14 @@ The following filters are available at the top of the alert list: Each view keeps its filter conditions and restores them when you refresh or return to the page. + +**Alert Title** matches as a **substring** and is case-sensitive. Entering `disk full` returns every alert whose title contains that string; the title does not have to match your input exactly. + +- A value containing `*` or `?` matches as a **wildcard** against the whole title: `*` matches any number of characters, `?` matches one, and every other character matches literally +- A value wrapped in `/…/` matches as a **RE2 regex** anywhere in the title; if the expression does not compile, it falls back to a substring match +- **A title filter covers at most 7 days.** If you set the time range to **Last 30 days** and then enter a title, the query is rejected with `the time range must not exceed 7 days when searching by title`. To look further back, split the period into runs of 7 days or less and query them one at a time + + ### View settings Click the view settings button at the top of the list to adjust the following options in the popup panel: diff --git a/en/on-call/incident/search-view-incident.mdx b/en/on-call/incident/search-view-incident.mdx index 473440d7..308c3d48 100644 --- a/en/on-call/incident/search-view-incident.mdx +++ b/en/on-call/incident/search-view-incident.mdx @@ -63,6 +63,12 @@ To improve performance, in aggregate view, the system matches at most **100** re - Search for incidents marked as "false positive" based on the false alarm field - Set **Unfinished actions / follow-ups** to **Yes** to surface incidents that still have open work to wrap up +**Labels** and **Custom fields** match **exactly**; wildcards and regex don't apply: + +- A label value must equal the value stored on the incident, case included. A value containing `*` or wrapped in `/…/` is compared literally: the system doesn't expand it into a wildcard or a regex, tells you the pattern isn't supported, and leaves that condition out of the query +- **Custom fields** list single-select, multi-select, and checkbox fields only, and their values also match exactly. Text fields can't be filtered by field; use **Search** instead +- For a partial match, use **Search** at the end of the filter bar. Wildcard and regex syntax applies only inside [Filter Conditions](/en/on-call/configuration/filter-conditions), which configure rules such as escalation, silence, and inhibit rules + For faster queries, narrow the time range and use conditions such as **Assigned to Me** and **Processing Progress** to reduce the scope. diff --git a/en/rum/analytics/custom-dashboards.mdx b/en/rum/analytics/custom-dashboards.mdx index 47bbd240..bd6e7fa7 100644 --- a/en/rum/analytics/custom-dashboards.mdx +++ b/en/rum/analytics/custom-dashboards.mdx @@ -23,12 +23,18 @@ The **+** menu at the right of the tab bar has two items: - **New dashboard**: opens an empty dashboard in edit mode. This needs the **Dashboards Manage** permission; without it, the item is not shown. - **Manage dashboards**: opens the management page; viewing it needs no edit permission. -The tab bar lists every dashboard by title, up to 100; beyond that, reach the rest from the management page. +The tab bar lists the **current application's** dashboards by title, up to 100; the rest, and other applications' dashboards, are reached from the management page. ## Application and time range -- A dashboard follows the **application** and **time range** in the top-right corner of the page. When you open a dashboard whose link carries no time range, the dashboard's own default time range applies; changing the time range on a dashboard also changes the page's time picker. -- Switching tabs carries the page's application and time range over. A dashboard's `env`, `service` and `version` variables and the matching filters of the built-in tabs are translated into each other; other variables are not carried across tabs. +A dashboard belongs to one application: creating it puts it in the application selected at the top right of the page, and every panel query reads that application. + +- The tab bar lists only the **current application's** dashboards; switch the page's application and the tab bar becomes that application's dashboards (possibly none). +- Switching the application on a dashboard tab leaves the dashboard: the page goes back to the **Overview** tab. +- Opening another application's dashboard (from the management page or a link someone shared) first switches the **application** at the top right to the one the dashboard belongs to, then opens it. +- A **clone** stays in the application of the dashboard it was cloned from. +- When you open a dashboard whose link carries no time range, the dashboard's own default time range applies; changing the time range on a dashboard also changes the page's time picker. +- Switching tabs carries the page's time range over. A dashboard's `env`, `service` and `version` variables and the matching filters of the built-in tabs are translated into each other; other variables are not carried across tabs. ## Panel types @@ -51,10 +57,10 @@ The panel editor's **Visualization** offers four kinds: Click **Add panel** to open the panel editor. A dashboard organizes panels into tabs and sections; a new dashboard starts with one tab. - Pick the application (or **Page application**), the event type, the aggregation and measured field, the group-by field and the number of groups to keep, then write a DQL filter if you need one. The preview runs once the query is complete: after a picker change it reruns once the change settles, and a DQL filter runs on Enter or blur. Saving does not require a successful preview. + Pick the event type, the aggregation and measured field, the group-by field and the number of groups to keep, then write a DQL filter if you need one. The preview runs once the query is complete: after a picker change it reruns once the change settles, and a DQL filter runs on Enter or blur. Saving does not require a successful preview. - A title you leave empty is generated from the query, such as "P75 Time to First Byte · by Browser Name"; an empty description becomes the application name as the panel subtitle, which tells panels querying different applications apart. + A title you leave empty is generated from the query, such as "P75 Time to First Byte · by Browser Name"; an empty description becomes the application the panel queries, as the panel subtitle. Click **Apply** to put the panel back on the canvas, then **Save** to submit. You can fill in a **version message** (optional); each save produces a new version. @@ -63,16 +69,19 @@ The panel editor's **Visualization** offers four kinds: ## Panel queries -A panel query has the same parts as the Explorer's analytics view: +A panel query has the same parts as the Explorer's analytics view. The application is not one of them: a panel's every query reads the application the dashboard belongs to, see [Application and time range](#application-and-time-range). | Part | Description | |------|-------------| -| **Application** | One application, or **Page application** (`$app`, so the panel follows the page's application) | | **Event type** | Sessions, Views, Resources, Actions, Errors, Long Tasks, Vitals | | **Aggregation / measured field** | Count, unique count, average, sum, min, max, P50 / P75 / P90 / P95 / P99; every aggregation except Count needs a field | | **Group-by field / top** | Split by a field and keep the top `5`, `10`, `20` or `50` groups | | **DQL filter** | The Explorer's search syntax, see [Data query syntax](../explorer/data-query) | + +Every query names the dashboard's own application ID. A query naming `$app` (resolved to the page's current application) or another application is rejected when the dashboard is saved. + + Group-by fields are limited by field cardinality, exactly as in the Explorer (see [Analytics · Group-by field](../explorer/analytics#group-by-field)): a field that is an event's own ID cannot be grouped by, and any other high-cardinality field takes Count or Sum only, with a time range of at most 7 days. When the result is estimated from a sample, the panel shows a **Sampled** badge and its explanation. @@ -83,7 +92,7 @@ The variable bar sits at the top of the dashboard. A new dashboard starts with t | Variable kind | Description | |---------------|-------------| -| Built-in `$app` | The page's current application. Choosing **Page application** in a panel query is the same as using `$app`; only an application's `application_id` can reference it | +| Built-in `$app` | Only present in a saved dashboard definition: a query whose `application_id` is `$app` resolves to the page's current application. There is no such option in a panel query, and a dashboard holding one is rejected when saved (see [Panel queries](#panel-queries)) | | Field variable | Candidates are the values of one RUM field; multi-select, All allowed | | Custom variable | Candidates you type in (one per line, `label=value` or a bare value); single or multi-select | @@ -102,7 +111,7 @@ A RUM dashboard has just these two kinds of custom variables: field variables th In the Explorer's analytics chart toolbar, **Save to dashboard** turns the current question into a dashboard panel: - The chart type can be **Time series / Table / Stat**; pies and distributions are not supported yet and the button says "Pies and distributions cannot be saved to a dashboard yet". -- You can **append to an existing dashboard** (its edit mode opens with this panel appended, and nothing is written before you save), or **create a new dashboard** (a dashboard holding just this panel is created first, then its edit mode opens). +- You can **append to an existing dashboard** (only the current application's are offered; its edit mode opens with this panel appended, and nothing is written before you save), or **create a new dashboard** (a dashboard holding just this panel is created first, then its edit mode opens). - The panel keeps the current time range and filter and picks up the dashboard's `env` / `service` / `version` variables; its title is generated from the query. For the procedure and limits, see [Analytics · Saving to a dashboard](../explorer/analytics#saving-to-a-dashboard). @@ -138,7 +147,9 @@ Creating, editing, deleting and restoring a dashboard needs the **Dashboards Man - the **+** menu has no **New dashboard**, and the management page has no **New dashboard** button and no delete or restore entry; - a dashboard has no **Edit**, and its **⋯** menu has no **Clone** or **Delete**; -- you can still view every dashboard, change its variables and time range, and inspect its content with **Export JSON** and **Version history**. +- you can still view the dashboards of the applications you can read, change their variables and time range, and inspect their content with **Export JSON** and **Version history**. + +A dashboard is also bound by application read permission: the dashboards of an application you cannot read are left out of the tab bar, the management page and the trash, and opening one directly says "Dashboard not found or not accessible". The account owner and administrators can read every application. For application read permission, see [Application management](../quickstart/app-management#application-permissions). ## Limits @@ -161,6 +172,9 @@ Creating, editing, deleting and restoring a dashboard needs the **Dashboards Man | Dashboard definition size | 1 MB | | Default time ranges | `now-15m`, `now-30m`, `now-1h`, `now-3h`, `now-6h`, `now-12h`, `now-24h`, `now-7d` | | Auto refresh options | off, `30s`, `1m`, `5m` | +| Concurrent data queries | 16 (shared by the whole account: each chart in the Explorer and each panel query of a dashboard takes one) | + +A query beyond the limit queues for a free slot, and the wait counts against the request's timeout; one still queued at the timeout fails, and its chart says **Query failed**. ## Next steps diff --git a/en/rum/error-tracking/error-aggregation.mdx b/en/rum/error-tracking/error-aggregation.mdx index f5b66fa6..b990243e 100644 --- a/en/rum/error-tracking/error-aggregation.mdx +++ b/en/rum/error-tracking/error-aggregation.mdx @@ -10,10 +10,10 @@ Flashduty groups error events with the same cause into one Issue, which reduces A new error event is assigned to an Issue in this order: 1. If its fingerprint matches an existing Issue, it joins that Issue. -2. If the fingerprint differs but the error is similar, it joins the most similar Issue. +2. If the fingerprint differs but the error is similar, it joins the most similar Issue. Similarity is compared only among Issues at the same error location. 3. If no Issue is similar, Flashduty creates a new Issue. -Android NDK native crashes, Electron process-gone events (`RenderProcessGone`, `ChildProcessGone`), and NDK crashes from Flutter and React Native apps are grouped by fingerprint only, without the similarity step. Their error messages are almost identical, so similarity grouping would merge crashes from different locations into one Issue. +Android NDK native crashes, iOS crashes, Electron process-gone events (`RenderProcessGone`, `ChildProcessGone`), and NDK crashes from Flutter and React Native apps are grouped by fingerprint only, without the similarity step. Their error messages are almost identical, so similarity grouping would merge crashes from different locations into one Issue. ## Default fingerprint @@ -25,11 +25,32 @@ When an error event doesn't carry a fingerprint, Flashduty calculates one from t | `env` | Environment where the error occurred | | `error.type` | Error type classification | | `error.message` | Error description text. For Android NDK native crashes, the topmost application-layer native frame in the stack also counts and system library frames do not, so the same crash location always groups into the same Issue. | +| Error location | Counted only for Web JavaScript errors, Android Java/Kotlin exceptions, and iOS crashes; see "Error location" below | When calculating the fingerprint, Flashduty ignores dynamic values in stack frames, such as version numbers, IDs, and dates. +## Error location + +The same error message can be thrown from unrelated places. Grouping by message alone puts every `Cannot read properties of undefined (reading 'id')` in an app into one Issue. Flashduty therefore also counts the error location in the fingerprint. + +The location keeps only what survives a rebuild: no line or column numbers, no build hashes, and no minified or obfuscated short names. + +| Platform | What the error location is | Example | +|----------|----------------------------|---------| +| Web | The topmost frame in the stack that resolves to a script: its script file name plus the function name, or the file name alone when the function name is minified to a short one. Build hashes, directory levels, and query strings are dropped; browser-extension frames and the RUM SDK's own instrumentation frames are skipped | `index.js:CartPage.render` | +| Android (Java/Kotlin exceptions) | The throw site of the innermost root cause of the exception chain, plus the first frame of app code below it. R8-obfuscated class and method names don't count | `com.example.chat.SessionStore.require` | +| iOS crashes | The crash site, plus the first frame of app code below it. Frames that carry the process to termination, such as `pthread_kill`, `abort`, and `__cxa_throw`, are skipped; when the stack never reaches app code, the site's caller stands in. A crash site without a symbol falls back to the image name plus its offset | `libobjc.A.dylib:objc_msgSend>QuantumApp:ChatCell.layoutSubviews()` | + +That offset is stable within a single build, so the same iOS crash can become a new Issue after every release. + +Handled errors and App Hangs on iOS take no error location: their message usually names the cause, and leaving the location out keeps existing Issues receiving them. Neither do Android NDK native crashes; they already group by the topmost application native frame. An error with no stable location, such as an Android exception with only obfuscated frames, keeps grouping by type and message alone, and is compared by similarity only with Issues that also have no error location. + + +The error location applies to messages first seen after this upgrade. A Web or Android Issue that existed before it still receives errors by type and message, and similarity grouping still covers it, so the Issue keeps its status, assignee, and history; no new Issue opens because the location entered the fingerprint. iOS crashes get no such carry-over: an old iOS Issue was keyed by the signal alone, so after the upgrade the same signal splits into several Issues by crash location. + + ## Custom fingerprint If default grouping doesn't meet your needs, you can fully control error grouping behavior by providing a custom fingerprint. diff --git a/en/rum/explorer/analytics.mdx b/en/rum/explorer/analytics.mdx index acf278ec..3b8d4cb2 100644 --- a/en/rum/explorer/analytics.mdx +++ b/en/rum/explorer/analytics.mdx @@ -100,6 +100,8 @@ From the top-right corner of the chart: - You can **append to an existing dashboard** (its edit mode opens with this panel appended, and nothing is written before you save), or **create a new dashboard** (a dashboard holding just this panel is created first, then its edit mode opens). - The panel keeps the current application, time range and filter, and picks up the dashboard's `env` / `service` / `version` variables; its title is generated from the query. +The query and chart you save here can also be built by AI first: describe it in one sentence in the query field, or let an AI SRE conversation set the measure, the group-by field and the chart type — see the [Data query syntax guide](/en/rum/explorer/data-query#query-and-analyze-with-ai-sre). + ## Distribution A **Distribution** buckets one numeric field by value range and shows the number of events in each range, without an aggregation or group-by. diff --git a/en/rum/explorer/data-query.mdx b/en/rum/explorer/data-query.mdx index 22deef42..138d0236 100644 --- a/en/rum/explorer/data-query.mdx +++ b/en/rum/explorer/data-query.mdx @@ -3,11 +3,27 @@ title: "Data query syntax guide" description: "Master Flashduty RUM Explorer search syntax to quickly locate and analyze user data through flexible query conditions." --- -RUM Explorer queries are made of **terms** and **operators** that combine into complex conditions; if you don't know the syntax yet, you can query in natural language instead. +RUM Explorer queries are made of **terms** and **operators** that combine into complex conditions; if you don't know the syntax yet, let AI write the query for you (see below). -## AI natural-language queries +## Querying with AI -If you don't know the query syntax, describe the data you want in plain Chinese or English. AI converts it into a standard query (DQL) with the same fields and syntax as a manual query. Click the **AI Natural-Language Query** (magic wand) icon on the left of the query field. You can also press ⌘ + Enter in normal query mode (Ctrl + Enter on Windows and Linux). The input border is highlighted while AI mode is active. +The entry point is the AI button on the left of the query field; in normal query mode you can also press ⌘ + Enter (Ctrl + Enter on Windows and Linux). Which panel it opens depends on the account: when AI SRE is enabled and you have access to AI SRE conversations, the button is **Open AI SRE** and opens an AI SRE conversation under the query field. When AI SRE is not enabled, or its credits are used up, the button is **AI natural language query** and opens the basic panel that turns one sentence into query conditions. + +### Query and analyze with AI SRE + +Say in one sentence what you want to look at; AI SRE writes the result onto the page itself — the query, the event type and the time range, and for charts the measure, the group-by field and the chart type as well. It then reads back what the page got and answers you, so you can keep asking about the same application. + +- **Status line**: while it works, it says what this step is — **Filling in the query**, **Checking** (against the real field values in the application), **Building the chart**, **Querying**. When the turn ends, the status line reports what the page got: **N found**, **Query complete, no data**, **Needs your input** (it is waiting for your answer), **Replied**, **Stopped**, **Query failed**, **Page changed, not applied**. +- **Undo change**: once AI SRE has written to the page, **Undo change** appears on the right of the status line and puts the query, the event type, the time range and the chart back the way they were before it started. The entry disappears once you edit the query field yourself — the page is then yours and is not undone; it is disabled while a turn runs. +- **Stop and collapse**: press **Stop** while a turn runs to end it; whatever was already written stays on the page. Click the status line to collapse or expand the conversation. A turn that wrote a query collapses the conversation when it ends, leaving the results in view; a turn that only answered in words expands so you can read it. +- **Follow-up and examples**: the status line offers the most likely next request — press Tab to fill it in, Enter to send. When AI SRE asks something back, the status line shows **Needs your input** and the input prompts you to reply. Before there is any conversation, a few example questions sit under the input: pick with ↑ ↓, press Tab to fill in, or Enter to send. +- **Draft while it runs**: pressing Enter before the turn ends only keeps a draft — "Still running; your draft is kept, send it when this finishes" — and you send it once the turn is over. +- **Another application is another conversation**: switching the application at the top right, or leaving the Explorer, ends this conversation, and the next one starts fresh; pressing the button again (it then reads **End this AI SRE conversation**) ends it too. +- **Credits and enablement**: when credits are used up (this period's allowance spent, wallet empty, or no On-call subscription), AI SRE cannot start a turn: its status line shows **Out of credits** with **Top up** (**Go to On-Call subscription** when the subscription is what is missing). After that the button opens the basic natural-language query instead, and the top of that panel states the reason in one line with the same link beside it. Accounts without AI SRE always get the basic query. + +### Basic natural-language query + +The button opens this basic panel when AI SRE is not enabled or out of credits: describe the data you want in plain Chinese or English and AI converts it into a standard query (DQL) with the same fields and syntax as a manual query. The input border is highlighted while this panel is active. @@ -26,16 +42,37 @@ If you don't know the query syntax, describe the data you want in plain Chinese You don't need to remember field names — AI picks the queryable fields for the current event type. - The preview shows the DQL condition to add. When the request better fits another event type (for example, "Switch event type to Errors") or time range, it also shows that change. If the result isn't right, refine your description and press Enter again to regenerate. + The preview shows the query AI returned: the whole query when the box was empty, only the added part (prefixed with `+`) when it extends the current query, and — when it replaces the current query — the old query struck through and labelled **Replaces the current query** with the full new query below it. When the request better fits another event type or time range (for example, "Switch event type to Errors"), that change gets its own old → new row. The preview also says how many events the query matches in the current time range; while it generates, the panel lists the steps the server is taking. If the result isn't right, refine your description and press Enter again to regenerate. - - Click **Apply**, **Append to Query**, or **Switch and Apply** to confirm the change. After applying, the confirmation message offers **Undo** to restore the previous query, event type, and time range. + + Click **Apply**, **Add to query**, **Replace query** or **Switch and apply** to confirm: the query goes into the query field, the event type and time range take effect in the same go, and the panel closes — the page then shows the new result. This basic query offers no undo; to get back to the page as it was before AI touched it, use **Undo change** in an AI SRE conversation (see [Query and analyze with AI SRE](#query-and-analyze-with-ai-sre)). -### Append instead of replace +#### Continuing from the current query + +When the query field already holds conditions, AI takes them into account and returns one **complete new query**, so it can both add to them and change them: + +- **Adding a condition** ("also 401", "only the last day"): the result is the current query plus the new condition, the preview shows only the added part (prefixed with `+`), and the button is **Add to query**. +- **Changing or dropping a condition** ("drop the duration condition", "only `/incident`", "switch to Safari"): the new query no longer contains some of the old conditions, so the preview strikes out the current query, labels it **Replaces the current query**, and the button becomes **Replace query**. +- **Changing the subject** (a request unrelated to the current conditions): AI ignores the current query and writes a new one for your description, which is applied the same replacing way. +- With an empty query field the button is just **Apply**; when the event type has to change it is **Switch and apply**, and the event type switches along with it. +- When the returned query is exactly what the box already holds and nothing else changes, the panel says "The query already says this". + +Before any result is generated, the bottom of the panel shows **Based on the current query** and the conditions in the box, so you can compare what this request changed. + +#### Check the count before applying + +Once the query is generated, the server runs it once against real data in the time range and the preview shows the outcome: + +- **N will match** when there is data; **Nothing matches in the current time range** (in warning colour) when there is none — you can still apply it. +- On zero hits AI first tries to correct itself: it checks case and spelling against the real values of those fields in this application (for example `Mobile`, `Mac OS X`) and, if needed, moves to a better-fitting field or event type — up to two rewrites. If it still matches nothing it returns the query as written: when your conditions are right and there is simply no such data, zero is the answer. +- While it works, the panel lists the steps the server is taking: **Understanding the request** › **Checking** › **Writing the query** › **Checking the count**; a rewrite shows **Rewriting the query** with its reason (**Nothing matched, trying another way**, **Switching to Pages**, **Fixing the query**, **Trying again**). +- If the count is unavailable it does not change the result: the query comes back as usual, just without a count. + +#### Analysis questions go to AI SRE -When the input already contains conditions, AI-generated conditions are **appended** rather than overwriting them, so you can add filters step by step in plain language. If the query is empty, the generated result is applied directly. +Requests that want a conclusion — "why is this page slow", "do we still get this error after the release", "how does this compare with last week", "which page is slowest" — cannot be answered by the query box. AI classifies them as a question rather than a filter condition and the panel says **This is a question for analysis; a query cannot answer it**, with the way to AI SRE beside it: **AI SRE can analyze this** plus **Enable AI SRE** when AI SRE is not enabled, or **Top up** / **Go to On-Call subscription** when credits are used up or the On-call subscription is missing. - Time expressions such as "last hour," "yesterday," and "past 7 days" update the Explorer time picker; they are not written as DQL conditions such as `client_time`. Performance-duration conditions remain DQL, for example `view_loading_time:>2s`. diff --git a/zh/ai-sre/sessions.mdx b/zh/ai-sre/sessions.mdx index f2700c5f..d041b393 100644 --- a/zh/ai-sre/sessions.mdx +++ b/zh/ai-sre/sessions.mdx @@ -67,7 +67,7 @@ sidebarTitle: "控制台对话" | 标记 | 含义 | |---|---| -| 旋转的圆圈 | Agent 正在运行 | +| 旋转的圆圈 | Agent 正在运行:当前回合在执行,或派发出去的子任务仍在跑 | | 🔭 + 数字 | 正在运行的后台任务数,见[任务面板与后台任务](#任务面板与后台任务) | | 蓝色小圆点 | 有您尚未查看的新内容,打开会话后消失 | | 相对时间 | 最近活动时间(如 `5m`、`3h`) | @@ -112,7 +112,9 @@ Agent 的回复会实时显示,包括文本、工具调用和思考过程。 ### 运行中继续输入(排队) -运行期间仍可以继续发送消息,消息会排队,在当前回合结束后依次执行。排队的消息显示在输入框上方,可以逐条编辑、移除或全部清空。Agent 开始处理某条消息后,就不能再撤回它;如需中断,请点击停止。 +**当前回合正在执行时**,仍可以继续发送消息,消息会排队,在当前回合结束后依次执行。排队的消息显示在输入框上方,可以逐条编辑、移除或全部清空。Agent 开始处理某条消息后,就不能再撤回它;如需中断,请点击停止。 + +**Agent 已经把活派给子任务、自己的回合先结束时**,会话仍算运行中(左侧列表照样显示旋转圆圈,输入框右侧也仍是停止按钮),但主 Agent 已经空闲:这时发送的消息**不会排队**,会立刻开始新的一轮。刷新页面后同样如此,不会被误判成“正在执行”而把消息压进队列。 ### 运行环境初始化 @@ -150,13 +152,24 @@ Agent 需要您澄清信息时,会在对话中插入提问卡片,可能是 有些控制台页面会**声明自己能被 AI 操作**:它把当前可用的动作清单和您所在的页面随每一轮消息发给 Agent,所以在这类页面上,Agent 不只给出文字建议,还能直接读取和填写页面上的表单。 -目前支持的是协作空间降噪处理下的 **告警聚合** 与 **抖动检测** 两页,见[告警降噪](/zh/on-call/channel/noise-reduction);其余页面没有页面动作,Agent 无法操作。页面动作只在控制台会话里存在,IM、API 和自动化会话中不会出现。 +目前声明了页面动作的控制台页面: + +| 页面 | Agent 能做什么 | +|---|---| +| 协作空间降噪处理下的 **告警聚合**、**抖动检测**(见[告警降噪](/zh/on-call/channel/noise-reduction)) | 读取表单,填写字段;保存这类立即生效的动作每次单独确认 | +| **RUM 查看器**(见 [用 AI SRE 查询和分析](/zh/rum/explorer/data-query#用-ai-sre-查询和分析)) | 核对字段取值、改写查询语句与事件类型、调整时间范围、配置聚合分析图表;写入直接落在页面上,用 **撤销修改** 还原 | + +其余页面没有页面动作,Agent 只能给出文字建议。页面动作只在控制台会话里存在,IM、API 和自动化会话中不会出现。 + +**告警聚合 / 抖动检测**页上的动作这样执行: - **读取**表单(字段、当前值、可选项、是否可写)不需要授权。 - **填写**字段只是把值写进表单,不会替您提交,您复核后自己点 **保存**。 - **保存**这类立即生效的动作,每次都在对话里单独弹出确认卡片(显示在输入框上方):列出「原值 → 新值」,按钮是 **取消** 和动作自带的动词(如 **保存**)。 -操作页面之前,Agent 会先用提问卡片问您这次改动怎么落地:填进表单由您复核后自己保存,还是直接保存。执行期间页面四周出现品牌色高亮,顶部出现 **AI 正在操作页面** 状态条,完成后变为 **已完成**;您也可以点 **停止** 中断。发出新消息或离开会话后,尚未答复的确认卡片自动失效。以只读方式打开他人分享的会话时,页面动作不会执行。 +在这两页上操作之前,Agent 会先用提问卡片问您这次改动怎么落地:填进表单由您复核后自己保存,还是直接保存。执行期间页面四周出现品牌色高亮,顶部出现 **AI 正在操作页面** 状态条,完成后变为 **已完成**;您也可以点 **停止** 中断。发出新消息或离开会话后,尚未答复的确认卡片自动失效。以只读方式打开他人分享的会话时,页面动作不会执行。 + +**RUM 查看器**上的写入不弹确认卡片:Agent 直接改写查询框、事件类型、时间范围和聚合分析图表并立即执行,查询框下方的 AI SRE 状态条显示进度与结果(**正在填入查询**、**正在查询**,完成后显示查到的条数、**查询完成** 或 **查询完成,暂无数据**)。要还原成写入前的页面,点状态条上的 **撤销修改**。只是核对某个字段有哪些取值时,Agent 不会改动页面。 ### 需要授权时 @@ -319,6 +332,17 @@ IM 和 API 会话不显示草稿卡,Agent 会在回复开头给出“审阅并 本节面向通过 [Open API](/zh/api-reference/ai-sre/sessions/session-read-info) 集成 AI SRE 会话的开发者。 +### 会话运行状态 + +`POST /safari/session/get` 与 `POST /safari/session/list` 都返回两个运行状态字段,含义不同: + +| 字段 | 含义 | +|---|---| +| `is_running` | 会话占着运行态:当前回合正在执行,**或**派发出去的子任务回合尚未结束。后台命令和监视器在跑不算 | +| `turn_in_flight` | 当前回合是否真的在执行 | + +Agent 把活派给子任务后,自己的回合会先结束,这段时间 `is_running` 仍为 `true`,`turn_in_flight` 为 `false`。判断「现在发消息会不会排队」看 `turn_in_flight`;判断「这个会话是不是还在干活」看 `is_running`。两个字段都在响应时计算,是查询那一刻的状态。 + ### 撤回排队消息 `POST /safari/session/get` 响应中的 `pending_messages` 字段是 Agent 尚未读取的排队消息(按执行顺序排列)。在 Agent 读取前,消息作者本人可以调用 `POST /safari/session/message/cancel` 撤回,请求体携带 `session_id` 与 `invocation_id`(发送消息时回执中的调用 ID)。响应的 `result` 字段: diff --git a/zh/changelog/changelog.mdx b/zh/changelog/changelog.mdx index abd23b0a..383400ca 100644 --- a/zh/changelog/changelog.mdx +++ b/zh/changelog/changelog.mdx @@ -4,6 +4,22 @@ description: "本页面记录 Flashduty 产品的重要更新和功能发布" keywords: ["更新日志", "产品发布", "功能更新", "Flashduty", "版本记录"] --- + + +### RUM 查看器:用 AI SRE 查询和分析 + +查询框左侧的星形(✦)按钮现在打开 AI SRE(账户已开通 AI SRE、且您有 AI SRE 会话权限时;在普通查询模式下按 ⌘ + Enter,Windows 和 Linux 为 Ctrl + Enter 也一样)。用一句话说明要查什么,AI SRE 就把它写进页面:查询框的条件、事件类型、时间范围,以及聚合分析下要画的图表,然后自己跑一次查询。查询框下方的状态栏报告这一轮进展——正在填入查询、正在查询(超过 3 秒开始计秒)、已查到 N 条、查询完成,暂无数据、查询失败、已停止;点 **撤销修改** 把页面退回它写入前的样子,只在查询框里仍是它写的内容时可用。**停止** 结束运行中的这一轮;点状态条或按 Esc 只收起对话,不会结束它,结果留在页面上。账户未开通 AI SRE 或额度不足时,同一个入口仍是基础自然语言查询:一句话生成 DQL,预览后再应用。详见[数据查询语法指南](/zh/rum/explorer/data-query)。 + +### RUM 看板:一个看板属于一个应用 + +自定义看板现在归属到创建它的那个应用,看板里每个面板的查询都只读这个应用,面板编辑器因此去掉了应用选择:原来的「跟随页面应用」(`$app`,按页面当前应用解析)只留在升级前保存的看板定义里。分析看板的页签栏只列当前应用的看板(按标题排序,最多 100 个),**管理看板** 页列出所有应用的看板;从管理页或链接打开别的应用的看板时,页面会先把应用切到那块看板所属的应用,再打开它。在看板页签上手动切换应用会离开这块看板,回到 **概览** 页签——它属于上一个应用。复制别的应用的看板,副本留在那个应用里。升级前保存的看板按它第一个读具体应用的查询归属;一个具体应用都读不到的旧看板不再出现在应用页签里,也不能再编辑,需要在目标应用下重建。详见 [RUM 自定义看板](/zh/rum/analytics/custom-dashboards)。 + +### RUM 异常按出错位置拆分 + +同一条错误消息从代码里两个不同位置抛出,现在会形成两个 Issue,不再合成一个。判断依据是能跨版本稳定复现的位置:Web JS 错误用最上层有意义堆栈帧的脚本名与函数名,Android 用异常链根因的抛出位置加下面第一个应用代码帧,iOS 崩溃用崩溃现场那一帧加下面第一个应用代码帧;行号、构建哈希、被压缩或混淆的名字都不参与,所以发新版本不会把同一个 bug 拆成新 Issue。认不出位置的压缩帧不按位置区分,这类错误仍按类型与消息聚合。iOS 崩溃里 SDK 没能还原出符号的帧只能按镜像内偏移区分,而偏移只在一个构建内稳定,这类崩溃每发一次版都可能变成一个新建的 Issue(上传 dSYM 只改变控制台里堆栈的显示,不影响聚合)。浏览器与 Android 上已有的 Issue 继续接收该消息来自任何位置的错误,保留状态、处理人与历史;iOS 崩溃不沿用旧的只按信号合并的 Issue,会按崩溃位置新建。自定义指纹的优先级仍然最高。详见[异常聚合](/zh/rum/error-tracking/error-aggregation)。 + + + ### 分派策略支持表格与卡片视图 @@ -20,7 +36,7 @@ keywords: ["更新日志", "产品发布", "功能更新", "Flashduty", "版本 ### RUM 自定义看板:在分析看板里自己搭看板 -分析看板(Insights)的页签栏不再只有内置看板:页签栏右上角的 **+** 菜单提供 **新建看板**(需「看板管理」权限)与 **管理看板**,自建看板作为额外页签打开,最多列出 100 个页签;聚合分析图表工具栏的 **保存到看板** 也能把当前问题直接加成整宽面板。面板问的就是查看器里的聚合分析问题——应用(或内置变量 `$app`,跟随页面当前应用)、事件类型、统计方式与统计字段、分组与取前 N,外加 DQL 过滤,可画时序图、表格、单值和文本面板。看板变量支持字段取值与自定义两类,在面板 DQL 里用 `${name}` 引用,新看板默认带 `env` / `service` / `version` 三个字段变量。每次保存留下一个版本(保留最近 20 个),删除的看板进回收站保留 30 天,可在管理页恢复。详见 [RUM 自定义看板](/zh/rum/analytics/custom-dashboards)。 +分析看板(Insights)的页签栏不再只有内置看板:页签栏右上角的 **+** 菜单提供 **新建看板**(需「看板管理」权限)与 **管理看板**,自建看板作为额外页签打开,最多列出 100 个页签;聚合分析图表工具栏的 **保存到看板** 也能把当前问题直接加成整宽面板。面板问的就是查看器里的聚合分析问题——事件类型、统计方式与统计字段、分组与取前 N,外加 DQL 过滤(一块看板归属一个应用,2026-10-25 起面板查询固定读该应用),可画时序图、表格、单值和文本面板。看板变量支持字段取值与自定义两类,在面板 DQL 里用 `${name}` 引用,新看板默认带 `env` / `service` / `version` 三个字段变量。每次保存留下一个版本(保留最近 20 个),删除的看板进回收站保留 30 天,可在管理页恢复。详见 [RUM 自定义看板](/zh/rum/analytics/custom-dashboards)。 ### 通知模板详情页改版与「发送测试」 diff --git a/zh/developer/cli.mdx b/zh/developer/cli.mdx index af003c8a..f54b5ec8 100644 --- a/zh/developer/cli.mdx +++ b/zh/developer/cli.mdx @@ -758,12 +758,16 @@ flashduty automation fire # 经 HTTP POST 触发器触 | `--disabled` | 以停用状态创建(默认启用) | | `--schedule-enabled` | 是否启用周期触发器(默认 `true`) | | `--http-post-trigger` | 创建并启用 HTTP POST 触发器;只传它且不带任何周期参数时,CLI 会写入占位 cron 并自动停用周期触发器 | +| `--war-room-trigger` | 创建并启用作战室创建触发器;必须同时传 `--war-room-channel-ids` 与 `--war-room-severities`,缺任一个会直接报错。只传它且不带任何周期参数时,CLI 同样写入占位 cron 并停用周期触发器(与 `--http-post-trigger` 一致);与 `--schedule` 等周期参数一起传时周期触发照常启用 | +| `--war-room-channel-ids` / `--war-room-severities` | 作战室触发器的匹配条件:监听的协作空间 ID(逗号分隔,至少一个)与严重程度(`Critical`、`Warning`、`Info`,逗号分隔,至少一个);创建触发器时两者必须一起给出 | | `--prompt` / `--prompt-file` | 任务提示词,二选一必填;`--prompt-file` 从文件读取(`-` 表示 stdin) | | `--environment-kind` / `--environment-id` | 运行环境:`cloud` 或 `byoc`(`byoc` 需配合 `--environment-id`);留空表示自动 | 从 IM 会话里创建规则时,省略 `--run-in` 即让服务端把规则绑定到当前会话,同时继承该会话的作用域;不需要(也不应该)自己传 chat、平台、集成或会话 ID——服务端负责解析并鉴权当前会话。绑定当前会话之后,每次普通运行都会新建一个执行会话,IM 集成建线程时也会新建线程,并始终留在创建时捕获的那个会话与不可变作用域上,而不是复用旧会话或旧线程;同一次运行的重试复用该次运行的执行身份。若运行发生时绑定会话的作用域已与规则不符,本次运行会被跳过,规则不会被搬到别的会话里执行。作战室触发的规则行为不变。由于每次运行都是全新上下文,提示词必须自带所需的聊天上下文(服务对象、团队、投递目标等),不要写「上文/上述」这类指代。执行位置与作用域一样创建后不可变更。 -`update` 可改字段:`--name`、`--prompt`/`--prompt-file`、`--schedule`/`--at`/`--weekday`/`--cron-expr`/`--timezone`、`--enable`/`--disable`、`--enable-schedule`/`--disable-schedule`、`--enable-http-post-trigger`/`--disable-http-post-trigger`、`--rotate-http-post-token`、`--environment-kind`/`--environment-id`。个人 / 团队作用域与执行位置(`--run-in`)创建后不可变更,`update` 不提供这两类参数。`update` 的 `--cron-expr` 与 `create` 同一约束:分钟位必须是 `0`–`59` 的单一整数,最快每小时一次,不支持分钟位的通配符、范围、列表与步长。 +作战室创建触发器在匹配的协作空间里创建作战室(IM 群聊)时拉起一次运行,这次运行的会话建在该作战室的群聊里、不在控制台——`--run-in` 对它不生效,执行环境也取群里已经选好的那个,规则上的执行环境不影响它。字段语义与运行表现见[自动化 · 作战室创建触发](/zh/ai-sre/automations#作战室创建触发war-room-created)。 + +`update` 可改字段:`--name`、`--prompt`/`--prompt-file`、`--schedule`/`--at`/`--weekday`/`--cron-expr`/`--timezone`、`--enable`/`--disable`、`--enable-schedule`/`--disable-schedule`、`--enable-http-post-trigger`/`--disable-http-post-trigger`、`--rotate-http-post-token`、`--enable-war-room-trigger`/`--disable-war-room-trigger`、`--war-room-channel-ids`/`--war-room-severities`、`--environment-kind`/`--environment-id`。`--enable-war-room-trigger` 与 `--disable-war-room-trigger` 互斥,同时传入会报错;`--war-room-channel-ids`/`--war-room-severities` 一旦传入就整体替换该触发器的过滤器,通过 `update` 首次创建作战室触发器时服务端要求两个列表都给出。个人 / 团队作用域与执行位置(`--run-in`)创建后不可变更,`update` 不提供这两类参数。`update` 的 `--cron-expr` 与 `create` 同一约束:分钟位必须是 `0`–`59` 的单一整数,最快每小时一次,不支持分钟位的通配符、范围、列表与步长。 `runs` 支持 `--status`(`queued`/`running`/`retrying`/`succeeded`/`partial`/`failed`/`skipped`/`abandoned`)、`--trigger-kind`(服务端取值 `schedule`/`debug`/`manual`/`http_post`/`oncall_incident`/`war_room_created`,其中 `war_room_created` 表示由作战室创建触发的运行)、`--since`/`--until`、`--page`、`--limit`。`fire` 用触发器的 Token 鉴权(`--token`,或环境变量 `FLASHDUTY_AUTOMATION_TRIGGER_TOKEN`),`--text` 传本次运行的上下文,`--data` 传完整 JSON 请求体(内联 JSON 或 `-` 读 stdin)。 diff --git a/zh/developer/go-sdk.mdx b/zh/developer/go-sdk.mdx index f6e1c7db..4282e0b2 100644 --- a/zh/developer/go-sdk.mdx +++ b/zh/developer/go-sdk.mdx @@ -206,6 +206,15 @@ client, err := flashduty.NewClientWithAccessToken(accessToken, - `AutomationRuleCreateRequest.TeamID`(`team_id`)是 `*int64`:显式传 0 表示个人作用域,大于 0 表示账户内的某个团队;省略时若存在已认证的 IM 会话则继承该会话的作用域,否则由服务端取常规默认值。`current-chat` 规则的作用域必须与该会话一致。 - `AutomationRuleUpdateRequest` 已不再包含 `TeamID`(同样没有 `RunIn`):作用域与执行位置创建后不可变。旧代码若在更新请求里设置 `TeamID`,删掉该行即可,否则无法编译。 +作战室创建触发器的字段在创建与更新两侧的语义不同: + +- 创建侧是普通值:`AutomationRuleCreateRequest.WarRoomTriggerEnabled`(`bool`)、`WarRoomChannelIDs`(`[]int64`)、`WarRoomSeverities`(`[]string`)。更新侧三者都是指针(`*bool` / `*[]int64` / `*[]string`),nil 表示该字段保持不变,非 nil 才会发送。 +- 服务端按「给了就建」判定:`WarRoomTriggerEnabled` 为 true,或 `WarRoomChannelIDs` 非空时,才会创建该触发器——此时协作空间列表与严重程度列表(`Critical` / `Warning` / `Info`)都必须非空,缺任一个会以参数错误拒绝;只给严重程度不会创建触发器。 +- 更新时传空切片等同于省略:服务端把空列表按未提供处理、保留原值,所以过滤条件只能用非空列表整体替换,无法用空数组清空。 +- 读回时 `AutomationRuleItem.WarRoomTriggerEnabled` 恒有值(没有该触发器时为 false),`WarRoomTriggerID`、`WarRoomChannelIDs`、`WarRoomSeverities` 则为空(`""` / 空切片)。 + +字段含义与触发时机见[自动化 · 作战室创建触发](/zh/ai-sre/automations#作战室创建触发war-room-created)。 + ### 规则分组 `client.RuleFolders` 覆盖 `/monit/folder/*` 的 6 个操作:`ReadList`(`POST /monit/folder/list`)与 `ReadHealth`(`POST /monit/folder/health`)不带请求体——前者返回扁平的 `[]FolderItem`,要用 `ParentID` / `ParentPath` 自行在客户端重建目录树(仪表盘与告警规则共用这棵树),后者返回 `FolderHealthOutput`,其中 `FolderHealthItem.HasIssue` 标记该分组或其可见后代是否有活跃告警或规则运行问题;写入侧 `WriteCreate`(`/monit/folder/create`)与 `WriteUpdate`(`/monit/folder/update`)返回 `FolderItem`,`WriteMove`(`/monit/folder/move`)与 `WriteDelete`(`/monit/folder/delete`)只返回 `*Response`。相关导出类型还有 `FolderCreateRequest`、`FolderUpdateRequest`、`FolderMoveRequest` 与 `FolderDeleteRequest`。 @@ -245,7 +254,7 @@ out, _, err := client.DataSources.ToolsInvoke(ctx, req) ### Prometheus 标签值 -`client.DataSources.ReadPrometheusLabelValues(ctx, dataSourceID, labelName)`(`GET /monit/prometheus/api/v1/label/{label_name}/values`,`monit-prometheus-read-label-values`)通过监控代理列出某个 Prometheus 兼容数据源上单个标签的全部取值:标签名放在 URL 路径上(SDK 会做路径转义),目标数据源由 `X-DSID` 请求头指定——SDK 用 `dataSourceID` 自动设置该头(传 `0` 或 `labelName` 为空都直接报错),ID 从 `/monit/datasource/list` 获取,必须是当前账户下 Prometheus 兼容类型的数据源。这是唯一一个成功响应体不是 Flashduty `{request_id, data}` 信封的方法:响应直接解码为 `PrometheusLabelValuesResponse`(`status` 为 `success` 时 `data` 是标签值字符串数组;为 `error` 时携带 `errorType` 与 `error`)。未到达数据源前的失败(`X-DSID` 缺失或非法、数据源不存在、数据源不是 Prometheus 类型)以 `text/plain` 返回,数据源自身的失败则用它自己的 JSON 错误形态;SDK 对两者一视同仁,把原始响应体原样放进 `*ErrorResponse.Message`。受支持的部署要求 monit-edge v0.35.0 及以上版本。 +`client.DataSources.ReadPrometheusLabelValues(ctx, dataSourceID, labelName)`(`GET /monit/prometheus/api/v1/label/{label_name}/values`,`monit-prometheus-read-label-values`)通过监控代理列出某个 Prometheus 兼容数据源上单个标签的全部取值:标签名放在 URL 路径上(SDK 会做路径转义),目标数据源由 `X-DSID` 请求头指定——SDK 用 `dataSourceID` 自动设置该头(传 `0` 或 `labelName` 为空都直接报错),ID 从 `/monit/datasource/list` 获取,必须是当前账户下 Prometheus 兼容类型的数据源。这是唯一一个成功响应体不是 Flashduty `{request_id, data}` 信封的方法:响应直接解码为 `PrometheusLabelValuesResponse`(`status` 为 `success` 时 `data` 是标签值字符串数组;为 `error` 时携带 `errorType` 与 `error`)。未到达数据源前的失败(`X-DSID` 非法、数据源不存在、数据源不是 Prometheus 类型)以 `text/plain` 返回,数据源自身的失败则用它自己的 JSON 错误形态;SDK 对两者一视同仁,把原始响应体原样放进 `*ErrorResponse.Message`。有两类情况不返回错误:请求不带 `X-DSID`,以及该数据源所在 monit-edge 集群里有实例版本低于 v0.35.0(不支持资源代理)——两者都返回 200 与空的 Prometheus 兼容结果,`/api/v1/labels`、`/api/v1/series`、`/api/v1/label/{label_name}/values` 的 `data` 是空数组,`/api/v1/metadata` 的 `data` 是空对象。也就是说读到空结果时不要当成「这个标签没有取值」,先确认 `X-DSID` 是否带上、edge 是否需要升级。受支持的部署要求 monit-edge v0.35.0 及以上版本。 ### 数据源配置 diff --git a/zh/on-call/comparison/vs-pagerduty.mdx b/zh/on-call/comparison/vs-pagerduty.mdx index ff235fdd..0effdf04 100644 --- a/zh/on-call/comparison/vs-pagerduty.mdx +++ b/zh/on-call/comparison/vs-pagerduty.mdx @@ -90,7 +90,7 @@ Response 解决「找到人之后怎么快速闭环」:一条时间线、一 | **故障重开** | 关闭后重新打开并通知 | ✅ **Flashduty 独有** | | **[自定义字段](/zh/on-call/configuration/custom-fields)** | 故障业务属性自由定义(标记误报、会议链接等),**支持按字段检索** | 两者均支持;PagerDuty 需先配置 Incident Types 并逐字段启用 | | **[自定义表单](/zh/on-call/configuration/custom-forms)** | 创建/认领/关闭故障时,按条件展示补充信息表单 | Flashduty 全流程支持;PagerDuty 仅关闭环节支持必填字段(限 Enterprise 档) | -| **检索能力** | 按标签、自定义字段、标题、人员检索 | Flashduty 支持精确、通配、正则匹配;PagerDuty 支持基础的字段过滤检索 | +| **检索能力** | 按标签、自定义字段、标题、人员检索 | Flashduty 的告警标题支持子串、通配与正则匹配,标签与自定义字段为精确匹配,人员按成员精确筛选;PagerDuty 支持基础的字段过滤检索 | ### Status Pages diff --git a/zh/on-call/incident/alert-management.mdx b/zh/on-call/incident/alert-management.mdx index 697640e0..a4200d9b 100644 --- a/zh/on-call/incident/alert-management.mdx +++ b/zh/on-call/incident/alert-management.mdx @@ -44,7 +44,7 @@ keywords: ["告警管理", "告警列表", "告警详情", "聚合视图", "告 | 筛选项 | 说明 | | :--- | :--- | -| **告警标题** | 按标题进行模糊匹配 | +| **告警标题** | 按标题子串匹配,也支持通配与正则写法(见下方说明) | | **严重程度** | 多选 Critical / Warning / Info | | **协作空间** | 按所属协作空间筛选 | | **集成** | 按告警来源集成筛选 | @@ -54,6 +54,14 @@ keywords: ["告警管理", "告警列表", "告警详情", "聚合视图", "告 筛选条件会按视图保留,刷新或重新进入页面后自动恢复。 + +**告警标题** 按**子串**匹配,且区分大小写。输入 `disk full` 会返回标题中包含该字符串的告警,不要求与标题完全一致。 + +- 值里含 `*` 或 `?` 时按**通配**匹配,需要匹配整个标题:`*` 匹配任意多个字符,`?` 匹配一个字符,其余字符按字面匹配 +- 值用 `/…/` 包裹时按 **RE2 正则**匹配,命中标题中的一段即可;正则写错时退回子串匹配 +- **标题筛选的时间范围最长 7 天**。时间范围选为 **最近 30 天** 之后再输入标题,查询会被拒绝,并返回 `the time range must not exceed 7 days when searching by title`。要看更长时间范围的告警时,请把区间拆成多段、每段不超过 7 天分别查询 + + ### 视图设置 点击列表顶部的视图设置按钮,可以在弹出的面板中调整以下选项: diff --git a/zh/on-call/incident/search-view-incident.mdx b/zh/on-call/incident/search-view-incident.mdx index ee9c88be..08cb27ad 100644 --- a/zh/on-call/incident/search-view-incident.mdx +++ b/zh/on-call/incident/search-view-incident.mdx @@ -64,6 +64,12 @@ keywords: ["故障检索", "故障列表", "聚合视图", "时间线", "故障 - 根据误报字段,检索被标记为"误报"的相关故障 - 将 **未完成的行动项/跟进项** 设为 **有**,集中查看仍有未完成工作项、尚未收尾的故障 +**标签** 与 **自定义字段** 都按**精确匹配**,不支持通配与正则: + +- 标签值必须与故障上存储的值完全一致(区分大小写)。值里带 `*` 或用 `/…/` 包裹时不会按通配或正则展开,只按这几个字符本身比较:系统会提示该写法不受支持,并且不把这条条件用于查询 +- **自定义字段** 只列出单选、多选、勾选三类字段,值同样精确匹配;文本字段无法按字段筛选,请改用 **键入检索** +- 需要模糊查找时用行尾的 **键入检索**。通配与正则写法只在[过滤条件](/zh/on-call/configuration/filter-conditions)里生效:分派策略、静默策略、抑制策略等规则的条件用的就是那套语法 + 为保证查询速度,建议缩小时间范围,并尽量用 **分派给我**、**处理进度** 等条件缩小查询范围。 diff --git a/zh/rum/analytics/custom-dashboards.mdx b/zh/rum/analytics/custom-dashboards.mdx index a4458393..0257b028 100644 --- a/zh/rum/analytics/custom-dashboards.mdx +++ b/zh/rum/analytics/custom-dashboards.mdx @@ -23,12 +23,18 @@ keywords: ["RUM", "自定义看板", "分析看板", "面板", "图表", "看板 - **新建看板**:打开一个空白看板的编辑态。需要**看板管理**权限,没有权限时该项不显示。 - **管理看板**:进入看板管理页;只是查看,不需要编辑权限。 -页签栏按标题顺序列出全部看板,最多 100 个;超过 100 个的看板从看板管理页进入。 +页签栏按标题顺序列出**当前应用**的看板,最多 100 个;更多看板、以及其他应用的看板从看板管理页进入。 ## 应用与时间范围 -- 看板跟随页面右上角的**应用**与**时间范围**。打开看板时如果链接里没有时间范围,使用看板自己的默认时间范围;在看板里调整时间范围会同步改变页面的时间选择器。 -- 切换页签时页面的应用与时间范围一并带过去。看板的 `env`、`service`、`version` 三个变量与内置页签的对应筛选条件互相转换,其他变量不跨页签保留。 +一块看板属于一个应用:新建时它落在页面右上角当前的应用里,面板的每条查询都读这个应用。 + +- 页签栏只列**当前应用**的看板;切换页面的应用,页签栏随之换成那个应用的看板(可能一个也没有)。 +- 在看板页签上切换应用等于离开这个看板:页面回到**概览**页签。 +- 打开别的应用的看板(从看板管理页或别人给的链接)时,页面先把右上角的**应用**切到该看板所属的应用,再打开它。 +- **克隆**出来的看板留在原看板所属的应用里。 +- 打开看板时如果链接里没有时间范围,使用看板自己的默认时间范围;在看板里调整时间范围会同步改变页面的时间选择器。 +- 切换页签时页面的时间范围一并带过去。看板的 `env`、`service`、`version` 三个变量与内置页签的对应筛选条件互相转换,其他变量不跨页签保留。 ## 面板类型 @@ -51,10 +57,10 @@ keywords: ["RUM", "自定义看板", "分析看板", "面板", "图表", "看板 点击 **添加图表** 打开面板编辑弹窗。看板按页签与分组组织面板,一个新看板自带一个页签。 - 选择应用(或**跟随页面应用**)、事件类型、统计方式与统计字段、分组字段与**取前**组数,再按需写 DQL 过滤条件。查询就绪后预览自动运行:选择类控件改动后延迟重跑,DQL 输入框按回车或失焦时运行。保存不要求预览成功。 + 选择事件类型、统计方式与统计字段、分组字段与**取前**组数,再按需写 DQL 过滤条件。查询就绪后预览自动运行:选择类控件改动后延迟重跑,DQL 输入框按回车或失焦时运行。保存不要求预览成功。 - 标题留空时按查询自动生成,例如「P75 首字节时间 · 按浏览器名称」;描述留空时以应用名作面板副标题,用来区分查询不同应用的面板。 + 标题留空时按查询自动生成,例如「P75 首字节时间 · 按浏览器名称」;描述留空时以面板查询的应用名作面板副标题。 在弹窗里点 **应用** 把面板放回画布,再点 **保存** 提交。保存时可以写**版本说明**(选填),一次保存产生一个新版本。 @@ -63,16 +69,19 @@ keywords: ["RUM", "自定义看板", "分析看板", "面板", "图表", "看板 ## 面板查询 -一条面板查询由以下部分组成,与查看器的聚合分析一致: +一条面板查询由以下部分组成,与查看器的聚合分析一致。应用不在这里选:看板属于哪个应用,它的每条查询就读那个应用,见[应用与时间范围](#应用与时间范围)。 | 组成 | 说明 | |------|------| -| **应用** | 具体某个应用,或**跟随页面应用**(`$app`,看板跟着页面的应用切换) | | **事件类型** | `Sessions`、`Views`、`Resources`、`Actions`、`Errors`、`Long Tasks`、`Vitals` | | **统计方式 / 统计字段** | 计数、去重计数、平均值、求和、最小值、最大值、P50 / P75 / P90 / P95 / P99;除计数外需要选统计字段 | | **分组字段 / 取前** | 按某个字段拆开,保留前 `5`、`10`、`20` 或 `50` 组 | | **DQL 过滤** | 与查看器的搜索语法一致,见[数据查询语法](../explorer/data-query) | + +每条查询都写看板自己的应用 ID。写成 `$app`(按页面的当前应用解析)或别的应用时,看板保存会被服务端拒绝。 + + 分组字段受字段基数限制,规则与查看器相同,见[聚合分析 · 分组字段](../explorer/analytics#分组字段):事件的 ID 字段不能用于分组,其他高基数字段只能配计数或求和且时间范围最长 7 天。 结果按抽样估算时,面板会显示**采样估算**标记与说明。 @@ -83,7 +92,7 @@ keywords: ["RUM", "自定义看板", "分析看板", "面板", "图表", "看板 | 变量类型 | 说明 | |----------|------| -| 内置 `$app` | 页面的当前应用。面板查询里选**跟随页面应用**就等于用 `$app`;只有应用的 `application_id` 能引用它 | +| 内置 `$app` | 只存在于已保存的看板定义里:查询的 `application_id` 写成 `$app` 时按页面的当前应用解析。面板查询里没有这个选项,含这类查询的看板保存会被拒绝(见[面板查询](#面板查询)) | | 字段变量 | 候选值取自某个 RUM 字段的取值,多选,「全部」可用 | | 自定义变量 | 手动填写候选值(每行一个,`显示名=值` 或纯值),单选或多选 | @@ -102,7 +111,7 @@ RUM 看板只有两种自定义变量:取某个 RUM 字段的取值的字段 在查看器的聚合分析图表工具栏里点 **保存到看板**,可以把当前这个分析问题直接固化成一个看板面板: - 图表类型可选**时序 / 表格 / 单值**;饼图与分布图暂不支持,按钮会提示「饼图和分布图还不能保存到看板」。 -- 可以**追加到现有看板**(打开该看板的编辑态并追加这个面板,保存前不写入任何数据),也可以**新建看板**(先创建只含这个面板的看板,再打开它的编辑态)。 +- 可以**追加到现有看板**(候选只有当前应用的看板;打开该看板的编辑态并追加这个面板,保存前不写入任何数据),也可以**新建看板**(先创建只含这个面板的看板,再打开它的编辑态)。 - 面板沿用当前的时间范围与过滤条件,并自动带上看板的 `env` / `service` / `version` 变量,标题按查询自动生成。 具体操作与限制见[聚合分析 · 保存到看板](../explorer/analytics#保存到看板)。 @@ -138,7 +147,9 @@ RUM 看板没有目录(文件夹):看板不做分组,管理页也没有 - 页签栏 **+** 菜单里没有**新建看板**,看板的管理页没有**新建看板**按钮与删除、恢复入口; - 看板右上角没有**编辑**,**⋯** 菜单里没有**克隆**与**删除**; -- 仍然可以查看全部看板、切换变量与时间范围,也可以用**导出 JSON** 与**版本历史**查看内容。 +- 仍然可以查看有权限的应用的看板、切换变量与时间范围,也可以用**导出 JSON** 与**版本历史**查看内容。 + +看板还受应用的读权限约束:读不到的应用,它的看板不出现在页签栏、看板管理页与回收站里,直接打开会提示「看板不存在或无权查看」。账户所有者与账户管理员可以读取全部应用。应用读权限见[应用管理](../quickstart/app-management#应用权限)。 ## 数值限制 @@ -161,6 +172,9 @@ RUM 看板没有目录(文件夹):看板不做分组,管理页也没有 | 看板定义大小 | 1 MB | | 默认时间范围可选值 | `now-15m`、`now-30m`、`now-1h`、`now-3h`、`now-6h`、`now-12h`、`now-24h`、`now-7d` | | 自动刷新可选值 | 不刷新、`30s`、`1m`、`5m` | +| 同时进行的数据查询 | 16(整个账户共享;查看器的每个图表、看板的每条面板查询各占一个) | + +超出的查询排队等空位,等待时间计入这次请求的超时;排到超时仍没排上,这次查询会失败,图表提示**查询失败**。 ## 下一步 diff --git a/zh/rum/error-tracking/error-aggregation.mdx b/zh/rum/error-tracking/error-aggregation.mdx index cb4fbf50..2f91cd83 100644 --- a/zh/rum/error-tracking/error-aggregation.mdx +++ b/zh/rum/error-tracking/error-aggregation.mdx @@ -11,10 +11,10 @@ Flashduty 将相同原因的错误事件聚合为一个 Issue,减少需要处 新错误事件按以下顺序归入 Issue: 1. 与已有 Issue 的指纹相同,归入该 Issue。 -2. 指纹不同但错误相似,归入最相似的 Issue。 +2. 指纹不同但错误相似,归入最相似的 Issue。相似度只在同一出错位置的 Issue 之间比较。 3. 没有相似的 Issue,创建新 Issue。 -Android NDK 原生崩溃、Electron 进程终止事件(`RenderProcessGone`、`ChildProcessGone`)和 Flutter、React Native 应用中的 NDK 崩溃只按指纹聚合,不做相似度归并。这类事件的错误消息几乎相同,按相似度归并会把不同位置的崩溃合为一个 Issue。 +Android NDK 原生崩溃、iOS 崩溃、Electron 进程终止事件(`RenderProcessGone`、`ChildProcessGone`)和 Flutter、React Native 应用中的 NDK 崩溃只按指纹聚合,不做相似度归并。这类事件的错误消息几乎相同,按相似度归并会把不同位置的崩溃合为一个 Issue。 ## 默认指纹 @@ -26,11 +26,32 @@ Android NDK 原生崩溃、Electron 进程终止事件(`RenderProcessGone`、` | `env` | 错误发生的环境 | | `error.type` | 错误的类型分类 | | `error.message` | 错误的描述文本。Android NDK 原生崩溃还会计入堆栈中最顶层的应用层原生帧,系统库帧不参与,因此同一崩溃位置始终聚合为同一 Issue。 | +| 出错位置 | 仅 Web 的 JS 错误、Android 的 Java/Kotlin 异常和 iOS 崩溃计入,见下文「出错位置」 | 计算指纹时,Flashduty 会忽略堆栈帧中的版本号、ID、日期等动态参数。 +## 出错位置 + +同一句错误消息可能从互不相关的地方抛出。只按消息聚合,应用里每一处 `Cannot read properties of undefined (reading 'id')` 都会落进同一个 Issue。因此 Flashduty 还把出错位置计入指纹。 + +位置只保留重新构建后仍然不变的部分:不带行号与列号,不带构建哈希,也不带压缩或混淆后的短名。 + +| 平台 | 出错位置取什么 | 形如 | +|------|----------------|------| +| Web | 堆栈中最靠上、且能定位到脚本的那一帧:脚本文件名加函数名,函数名被压缩成短名时只按脚本名区分。构建哈希、目录层级和查询串被去掉,浏览器扩展与 RUM SDK 自身的埋点帧被跳过 | `index.js:CartPage.render` | +| Android(Java/Kotlin 异常) | 异常链最内层根因异常的抛出位置,加上其下第一个应用代码帧。R8 混淆后的类名与方法名不参与 | `com.example.chat.SessionStore.require` | +| iOS 崩溃 | 崩溃现场,加上其下第一个应用代码帧。`pthread_kill`、`abort`、`__cxa_throw` 这类把进程带向终止的帧被跳过;堆栈里没有应用代码时,取崩溃现场的下一帧。崩溃现场没有符号时退化为镜像名加偏移 | `libobjc.A.dylib:objc_msgSend>QuantumApp:ChatCell.layoutSubviews()` | + +这个偏移只在单次构建内稳定,因此同一个 iOS 崩溃在每次发版后都可能变成一个新建的 Issue。 + +iOS 上已处理的错误与 App Hang 不取出错位置:这类消息本身通常说明了原因,不取位置才能让已有 Issue 继续接收它们。Android NDK 原生崩溃也不取,它已按堆栈中最顶层的应用原生帧聚合。取不出稳定位置的错误(例如只有混淆帧的 Android 异常)仍只按类型和消息聚合,也只与同样没有出错位置的 Issue 做相似度归并。 + + +出错位置对本次升级之后首次出现的消息生效。升级前已存在的 Web 与 Android Issue 仍按类型和消息接收错误,相似度归并也仍然覆盖它们,因此这些 Issue 保留原有的状态、负责人和处理历史,不会因为位置进入指纹而重新开一个 Issue。iOS 崩溃没有这条保留规则:旧的 iOS Issue 只按信号聚合,升级后同一信号会按崩溃位置分成多个 Issue。 + + ## 自定义指纹 若默认聚合无法满足需求,您可以通过提供自定义指纹(fingerprint)完全控制错误的聚合行为。 diff --git a/zh/rum/explorer/analytics.mdx b/zh/rum/explorer/analytics.mdx index 238fa157..fef574d2 100644 --- a/zh/rum/explorer/analytics.mdx +++ b/zh/rum/explorer/analytics.mdx @@ -100,6 +100,8 @@ RUM 查看器提供**列表**与**分析**两种查看方式。**分析**视图 - 可以**追加到现有看板**(打开该看板的编辑态并追加这个面板,保存前不写入任何数据),也可以**新建看板**(先创建只含这个面板的看板,再打开它的编辑态)。 - 面板沿用当前的应用、时间范围与过滤条件,并自动带上看板的 `env` / `service` / `version` 变量;标题按查询自动生成。 +这里保存的查询条件和图表也可以先交给 AI 搭好:在查询框里用一句话描述,或让 AI SRE 对话直接设好统计方式、分组与图表类型,见[数据查询语法指南](/zh/rum/explorer/data-query#用-ai-sre-查询和分析)。 + ## 分布图 **分布图**按一个数值字段的取值区间分桶,展示每个区间的事件数,不使用统计方式和分组。 diff --git a/zh/rum/explorer/data-query.mdx b/zh/rum/explorer/data-query.mdx index d092ac77..f7714d6a 100644 --- a/zh/rum/explorer/data-query.mdx +++ b/zh/rum/explorer/data-query.mdx @@ -4,11 +4,27 @@ description: "掌握 Flashduty RUM 查看器的搜索语法,通过灵活的查 keywords: ["RUM", "数据查看器", "用户监控", "前端监控"] --- -RUM 查看器的查询由**词项**(terms)和**操作符**(operators)组成,可以组合出复杂的检索条件;不熟悉语法时也可以用自然语言查询。 +RUM 查看器的查询由**词项**(terms)和**操作符**(operators)组成,可以组合出复杂的检索条件;不熟悉语法时也可以让 AI 代写,见下方。 -## AI 自然语言查询 +## 用 AI 查询 -不熟悉查询语法时,可以直接用自然语言(中英文均可)描述要找的数据,AI 会将其转换为标准查询语句(DQL),字段与语法与手动查询完全一致。点击查询框左侧的 **AI 自然语言查询**(魔法棒)图标进入,或在普通查询模式下按 ⌘ + Enter(Windows 和 Linux 为 Ctrl + Enter);进入后输入框边框会高亮。 +入口是查询框左侧的 AI 按钮,也可以在普通查询模式下按 ⌘ + Enter(Windows 和 Linux 为 Ctrl + Enter)。它打开哪个面板取决于账户:账户已开启 AI SRE、且当前成员有 AI SRE 会话的访问权限时,按钮是 **打开 AI SRE**,打开的是查询框下方的一段 AI SRE 对话;未开启 AI SRE 或额度用尽时,按钮是 **AI 自然语言查询**,打开的是把一句话转成查询条件的基础面板。 + +### 用 AI SRE 查询和分析 + +一句话说清要看什么即可,AI SRE 自己把结果写到页面上:查询语句、事件类型和时间范围,需要图表时连统计方式、分组和图表类型一起设好;写完它会把页面查到的结果读回来答复您,所以可以接着追问同一个应用里的其他问题。 + +- **状态条**:运行中显示它这一步在做什么——**正在填入查询**、**正在核对**(对照应用里的真实字段取值)、**正在生成图表**、**正在查询**。本轮结束后状态条报告页面拿到了什么:**已查到 N 条**、**查询完成,暂无数据**、**需要补充**(它在等您回答)、**已回复**、**已停止**、**查询失败**、**页面已变化,尚未应用**。 +- **撤销修改**:AI SRE 写过页面之后,状态条右侧出现 **撤销修改**,把查询条件、事件类型、时间范围和图表恢复成它动手之前的样子。您在查询框里自己改过内容后这个入口消失——此时页面上的内容归您,不再撤销;运行中它不可点。 +- **停止与收起**:运行中点 **停止** 结束本轮,已经写上去的内容留在页面上。点状态条可以收起或展开对话;写过查询的一轮结束后对话自动收起,把结果留在视野里,只回答问题的那一轮会展开供您阅读。 +- **追问与示例**:状态条会给出下一句最可能的追问,按 Tab 填入输入框,回车发送;AI SRE 反问时状态条显示 **需要补充**,输入框提示您回复它。还没有对话时,输入框下方给出几个示例问题,用 ↑ ↓ 选择、Tab 填入、回车直接发送。 +- **运行中先写草稿**:本轮结束前按回车只会留下草稿,提示「当前仍在运行,草稿已保留,完成后再发送」,等本轮结束后再发。 +- **换应用就是换对话**:切换右上角的应用或离开查看器都会结束本次对话,再次打开是一个新对话;再点一次这个按钮(此时提示 **结束本次 AI SRE 对话**)也会结束它。 +- **额度与未开通**:额度用尽(本周期额度用完、钱包余额不足,或 On-Call 订阅缺失)时 AI SRE 起不了新一轮:对话里状态条显示 **额度不足** 并给出 **去充值**(On-Call 订阅缺失时为 **前往 On-Call 订阅**);此后这个按钮改为打开基础的自然语言查询,面板顶部用一句话说明原因,右侧是同一个入口。未开启 AI SRE 的账户一直走基础查询。 + +### 基础自然语言查询 + +账户未开启 AI SRE 或额度用尽时,这个按钮打开的是下面这一套基础面板:用自然语言(中英文均可)描述要找的数据,AI 把它转成标准查询语句(DQL),字段与语法与手动查询完全一致。进入后输入框边框会高亮。 @@ -27,16 +43,37 @@ RUM 查看器的查询由**词项**(terms)和**操作符**(operators)组 您无需记住字段名,AI 会按当前事件类型选择可查询的字段。 - 预览显示将要加入的 DQL 条件;当请求更适合其他事件类型(如提示「将切换事件类型为 错误」)或时间范围时,也会显示相应变更。结果不理想时,修改描述后再次回车即可重新生成。 + 预览给出 AI 返回的这条查询:查询框为空时整条显示;在原查询上补充条件时只显示新增的部分(前面带 `+`);要替换原查询时把原查询划掉并标注 **替换当前查询**,整条新查询显示在下面。请求更适合其他事件类型或时间范围时(如提示「将切换事件类型为 错误」),另外给出对应的 旧 → 新 一行。预览里还会给出这条查询在当前时间范围内会查到多少条;生成过程中面板逐条显示服务端正在做的步骤。结果不理想时,修改描述后再次回车即可重新生成。 - - 点击 **应用**、**追加到查询** 或 **切换并应用** 确认变更。应用后,提示消息中提供 **撤销**,可恢复应用前的查询、事件类型和时间范围。 + + 点击 **应用**、**追加到查询**、**替换查询** 或 **切换并应用** 确认变更:查询写入查询框,事件类型和时间范围一并生效,面板随即关闭,页面上显示的就是新的结果。这套基础查询不提供撤销;需要回到 AI 动手之前的页面,请用 AI SRE 对话里的 **撤销修改**(见[用 AI SRE 查询和分析](#用-ai-sre-查询和分析))。 -### 追加而非替换 +#### 在现有查询上继续改 + +查询框里已有条件时,AI 会把当前查询一起带上去理解,返回的是一条**完整的新查询**,因此既能补充条件,也能删改: + +- **补充条件**(如「再加上 401」「只看最近 1 天」):返回的是「原查询 + 新条件」,预览只显示新增的部分(前面带 `+`),按钮是 **追加到查询**。 +- **删改条件**(如「去掉耗时条件」「只看 `/incident`」「换成 Safari」):返回的新查询不再包含原查询里的某些条件,预览把原查询划掉并标注 **替换当前查询**,按钮变成 **替换查询**。 +- **换一个话题**(与当前条件无关的描述):AI 忽略现有条件,按新描述生成一条新查询,同样以替换的方式应用。 +- 查询框为空时按钮就是 **应用**;需要换事件类型时按钮是 **切换并应用**,应用后连同事件类型一起切过去。 +- 返回的查询与当前查询完全一致、又没有别的变更时,面板提示「当前查询已经是这个条件」。 + +还没有生成结果时,面板底部会标出 **基于当前查询** 和查询框里的原条件,便于对照这次到底改了什么。 + +#### 应用前先看条数 + +生成完成后,服务端会先用这条查询在时间范围内真实跑一次计数,结果直接出现在预览里: + +- 有数据时显示 **将查到 N 条**;一条都没有时显示 **当前时间范围内没有匹配的数据**(黄色提示),此时仍可应用。 +- 命中为 0 时 AI 会先自行修正:对着该应用里这些字段的真实取值核对大小写与拼写(例如 `Mobile`、`Mac OS X`),必要时换到更合适的字段或事件类型,最多重写两次;仍然为 0 就照原样返回——您要的条件本身正确、只是没有这样的数据时,0 条就是答案。 +- 生成过程中面板逐条显示服务端正在做的事:**理解问题** › **正在核对** › **生成查询** › **核对条数**;重写时显示 **重新生成查询** 和原因(**没查到数据,换个写法**、**改查「页面」**、**查询有误,修正中**、**再试一次**)。 +- 计数拿不到时不影响结果:查询照常返回,只是不显示条数。 + +#### 分析类问题交给 AI SRE -输入框中已有查询条件时,AI 生成的条件会**追加**到现有查询之后,不会覆盖,因此可以用自然语言逐步补充筛选条件;空查询时直接应用生成结果。 +「为什么这个页面变慢了」「上线后还有这个错误吗」「和上周比如何」「哪个页面最慢」这类要结论的请求,基础查询给不出答案:AI 判定这是在要结论、不是要筛条件,面板提示 **这是个分析问题,查询框给不出结论**,并给出通往 AI SRE 的入口——未开启 AI SRE 时后面跟一句 **AI SRE 可以帮你分析** 和 **开通 AI SRE**;额度不足或 On-Call 订阅缺失时是 **去充值** 或 **前往 On-Call 订阅**。 - “最近 1 小时”“昨天”“过去 7 天”等时间表达会更新查看器的时间选择器,不会被写成 `client_time` 等 DQL 条件;性能时长条件仍属于 DQL,例如 `view_loading_time:>2s`。