[9.5] fix: escape service name in APM linked dashboard filters (#291091) - #291180
Merged
Merged
Conversation
) ## Summary Closes elastic#245023 Linking a custom dashboard to an APM service whose name contains a colon (e.g. `unknown_service:java`) broke the Dashboards tab with `Expected AND, OR, end of input but ":" found. service.name: unknown_service:java (500)` — and once such a link existed, **no** service could show its linked dashboards. Two distinct defects: 1. **Unescaped KQL is persisted.** `save_dashboard_modal.tsx` stored `` `${SERVICE_NAME}: ${serviceName}` `` — the service name comes straight off the URL path param, so a colon (and also spaces, `(`, `)`, `"`, `*`, `and`/`or`/`not`) produced invalid KQL. It's now stored as a quoted phrase via `escapeQuotes`, matching the existing APM precedents in `build_alert_filters.ts` and `service_flyout/footer/hooks/use_alerts_href.ts`. 2. **One bad saved object failed the route for every service.** The read route loads *all* linked dashboards globally and maps `kqlQuery(dashboard.kuery)` over them to build a single msearch. `kqlQuery` calls `fromKueryExpression`, which throws synchronously, so `GET /internal/apm/services/{serviceName}/dashboards` 500'd regardless of which service was being viewed. `getServicesWithDashboards` now guards each dashboard individually: an unparseable stored filter is skipped and logged instead of failing the request. The positional response loop was replaced with a paired array so indices stay aligned when a dashboard is dropped. The rendering path was never at fault — `getFilters` builds DSL via `buildPhraseFilter`/`buildExistsFilter` and is already colon-safe. The stored `kuery` is only ever read server-side. ### Upgrade note There is deliberately **no saved-object migration**. Unrelated services recover immediately, but a dashboard linked to a colon-named service *before* this fix keeps its broken stored filter and stays hidden until it is re-linked. ## Testing 24 new Jest tests across three files: - `common/utils/service_name_to_kuery.test.ts` — escaping for colons, spaces, quotes, backslashes and KQL keywords, each asserted to survive `fromKueryExpression` - `server/routes/custom_dashboards/get_services_with_dashboards.test.ts` — a malformed stored filter is skipped rather than thrown, unrelated dashboards still returned, and response/dashboard indices stay aligned when a middle entry is dropped - `actions/save_dashboard_modal.test.tsx` — drives the modal and asserts the persisted `kuery` Reverting the source fix makes exactly 5 of these fail (the regression cases); the 3 covering pre-existing behaviour still pass. ### Reproducing manually A new synthtrace scenario generates colon-named services alongside a plainly-named control service: ``` node scripts/synthtrace trace_with_service_names_with_colons --live ``` Link a dashboard to `synth-node`, then to `unknown_service:java`, and confirm both still render. To exercise the bad-data path, set an `apm-custom-dashboards` saved object's `kuery` to the unquoted form and check the route returns 200 with a warning logged instead of 500. <img width="1899" height="950" alt="image" src="https://github.com/user-attachments/assets/03c6738c-7b27-4c0a-9f2d-eba21a7ef449" /> https://github.com/user-attachments/assets/d73dfca4-02c7-45d2-b744-88178f0714d5 The scenario emits only transactions, spans and errors. App metrics are omitted on purpose: they route to `metrics-apm.app.<service.name>-<namespace>`, and Elasticsearch rejects a data stream name containing `:`, so those documents would all be dropped. Aggregated metricsets derived from the transactions still provide `processor.event: metric` coverage, which is what the dashboards route needs. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit f4fe32c)
kibanamachine
enabled auto-merge (squash)
September 15, 2026 14:48
|
Pinging @elastic/obs-presentation-team (Team:obs-presentation) |
Contributor
Author
Selected for Libra reviewThis PR was selected for Libra review as part of the temporary 50% trial. To opt out permanently, remove the |
Contributor
Author
💚 Build Succeeded
Metrics [docs]Module Count
Async chunks
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backport
This will backport the following commits from
mainto9.5:Questions ?
Please refer to the Backport tool documentation