-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[APM] Use excluded data tiers setting (#192373)
closes [#190559](#190559) ## Summary This PR updates the ES clients in APM to respect the excluded tier configuration. When this config is set, the ES clients will automatically add a filter to exclude the specified tiers from queries. <img width="600" alt="image" src="https://github.com/user-attachments/assets/9b0de76d-242c-4343-bc30-d5c787316f59"> All queries in APM should have the `_tier` filter (via `get_apm_events_client`) <img width="600" alt="image" src="https://github.com/user-attachments/assets/c525602f-f239-4be8-99c4-65d617962656"> This change also affects alerting (via `alerting_es_client`) <img width="600" alt="image" src="https://github.com/user-attachments/assets/750df4d7-5b49-4de5-9294-7afedf11d7e5"> And it impacts the alerts column (via `get_apm_alert_client`) <img width="600" alt="image" src="https://github.com/user-attachments/assets/44bd9129-1e72-4a3a-af32-d42a9cd9164d"> ### What won't automatically add a filter for `_tier` - Embeddables - ML queries ### How to test - Set the config in Advanced Settings to exclude `data_frozen` and `data_cold` (optional) - Navigate to APM and check the query `Inspect` to see if the filter is present. - Click through APM to confirm things still work. - Create one of each type of APM alerts - Without the config set, queries should not include the `_tier` filter` --------- Co-authored-by: Elastic Machine <[email protected]>
- Loading branch information
1 parent
886d009
commit ee5ef81
Showing
25 changed files
with
612 additions
and
117 deletions.
There are no files selected for viewing
This file contains 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
26 changes: 26 additions & 0 deletions
26
x-pack/packages/observability/observability_utils/es/queries/exclude_tiers_query.ts
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import type { estypes } from '@elastic/elasticsearch'; | ||
|
||
export function excludeTiersQuery( | ||
excludedDataTiers: Array<'data_frozen' | 'data_cold' | 'data_warm' | 'data_hot'> | ||
): estypes.QueryDslQueryContainer[] { | ||
return [ | ||
{ | ||
bool: { | ||
must_not: [ | ||
{ | ||
terms: { | ||
_tier: excludedDataTiers, | ||
}, | ||
}, | ||
], | ||
}, | ||
}, | ||
]; | ||
} |
This file contains 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
95 changes: 95 additions & 0 deletions
95
x-pack/plugins/observability_solution/apm/server/lib/helpers/get_apm_alerts_client.test.ts
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { type ApmAlertsRequiredParams, getApmAlertsClient } from './get_apm_alerts_client'; | ||
import type { | ||
IScopedClusterClient, | ||
IUiSettingsClient, | ||
KibanaRequest, | ||
SavedObjectsClientContract, | ||
} from '@kbn/core/server'; | ||
import { AlertsClient, RuleRegistryPluginStartContract } from '@kbn/rule-registry-plugin/server'; | ||
|
||
describe('get_apm_alerts_client', () => { | ||
let ruleRegistryMock: jest.Mocked<RuleRegistryPluginStartContract>; | ||
let alertClient: jest.Mocked<AlertsClient>; | ||
let uiSettingsClientMock: jest.Mocked<IUiSettingsClient>; | ||
|
||
const params: ApmAlertsRequiredParams = { | ||
size: 10, | ||
track_total_hits: true, | ||
query: { | ||
match: { field: 'value' }, | ||
}, | ||
}; | ||
|
||
beforeEach(async () => { | ||
uiSettingsClientMock = { | ||
get: jest.fn().mockResolvedValue(undefined), | ||
} as unknown as jest.Mocked<IUiSettingsClient>; | ||
|
||
alertClient = { | ||
find: jest.fn().mockResolvedValue({}), | ||
getAuthorizedAlertsIndices: jest.fn().mockResolvedValue(['apm']), | ||
} as unknown as jest.Mocked<AlertsClient>; | ||
|
||
ruleRegistryMock = { | ||
getRacClientWithRequest: jest.fn().mockResolvedValue(alertClient), | ||
alerting: jest.fn(), | ||
} as unknown as jest.Mocked<RuleRegistryPluginStartContract>; | ||
}); | ||
|
||
afterEach(() => { | ||
jest.resetAllMocks(); | ||
}); | ||
|
||
// Helper function to create the APM alerts client | ||
const createApmAlertsClient = async () => { | ||
return await getApmAlertsClient({ | ||
context: { | ||
core: Promise.resolve({ | ||
uiSettings: { client: uiSettingsClientMock }, | ||
elasticsearch: { client: {} as IScopedClusterClient }, | ||
savedObjects: { client: {} as SavedObjectsClientContract }, | ||
}), | ||
} as any, | ||
plugins: { | ||
ruleRegistry: { | ||
start: jest.fn().mockResolvedValue(ruleRegistryMock), | ||
setup: {} as any, | ||
}, | ||
} as any, | ||
request: {} as KibanaRequest, | ||
}); | ||
}; | ||
|
||
it('should call search', async () => { | ||
const apmAlertsClient = await createApmAlertsClient(); | ||
|
||
await apmAlertsClient.search(params); | ||
|
||
const searchParams = alertClient.find.mock.calls[0][0] as ApmAlertsRequiredParams; | ||
expect(searchParams.query).toEqual({ match: { field: 'value' } }); | ||
}); | ||
|
||
it('should call search with filters containing excluded data tiers', async () => { | ||
const excludedDataTiers = ['data_warm', 'data_cold']; | ||
uiSettingsClientMock.get.mockResolvedValue(excludedDataTiers); | ||
|
||
const apmAlertsClient = await createApmAlertsClient(); | ||
|
||
await apmAlertsClient.search(params); | ||
|
||
const searchParams = alertClient.find.mock.calls[0][0] as ApmAlertsRequiredParams; | ||
expect(searchParams.query?.bool).toEqual({ | ||
must: [ | ||
{ match: { field: 'value' } }, | ||
{ bool: { must_not: [{ terms: { _tier: ['data_warm', 'data_cold'] } }] } }, | ||
], | ||
}); | ||
}); | ||
}); |
This file contains 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
This file contains 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
93 changes: 93 additions & 0 deletions
93
x-pack/plugins/observability_solution/apm/server/routes/alerts/alerting_es_client.test.ts
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { type APMEventESSearchRequestParams, alertingEsClient } from './alerting_es_client'; | ||
import type { RuleExecutorServices } from '@kbn/alerting-plugin/server'; | ||
import type { ElasticsearchClient, IUiSettingsClient } from '@kbn/core/server'; | ||
import type { ESSearchResponse } from '@kbn/es-types'; | ||
|
||
describe('alertingEsClient', () => { | ||
let scopedClusterClientMock: jest.Mocked<{ | ||
asCurrentUser: jest.Mocked<ElasticsearchClient>; | ||
}>; | ||
|
||
let uiSettingsClientMock: jest.Mocked<IUiSettingsClient>; | ||
|
||
const params = { | ||
body: { | ||
size: 10, | ||
track_total_hits: true, | ||
query: { | ||
match: { field: 'value' }, | ||
}, | ||
}, | ||
}; | ||
|
||
const mockSearchResponse = { | ||
hits: { | ||
total: { value: 1, relation: 'eq' }, | ||
hits: [{ _source: {}, _index: '' }], | ||
max_score: 1, | ||
}, | ||
took: 1, | ||
_shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, | ||
timed_out: false, | ||
} as unknown as ESSearchResponse<unknown, typeof params>; | ||
|
||
beforeEach(() => { | ||
scopedClusterClientMock = { | ||
asCurrentUser: { | ||
search: jest.fn().mockResolvedValue(mockSearchResponse), | ||
} as unknown as jest.Mocked<ElasticsearchClient>, | ||
}; | ||
|
||
uiSettingsClientMock = { | ||
get: jest.fn().mockResolvedValue(undefined), | ||
} as unknown as jest.Mocked<IUiSettingsClient>; | ||
}); | ||
|
||
afterEach(() => { | ||
jest.resetAllMocks(); | ||
}); | ||
|
||
// Helper function to perform the search | ||
const performSearch = async (searchParams: APMEventESSearchRequestParams) => { | ||
return await alertingEsClient({ | ||
scopedClusterClient: scopedClusterClientMock as unknown as RuleExecutorServices< | ||
never, | ||
never, | ||
never | ||
>['scopedClusterClient'], | ||
uiSettingsClient: uiSettingsClientMock, | ||
params: searchParams, | ||
}); | ||
}; | ||
|
||
it('should call search with default params', async () => { | ||
await performSearch(params); | ||
|
||
const searchParams = scopedClusterClientMock.asCurrentUser.search.mock | ||
.calls[0][0] as APMEventESSearchRequestParams; | ||
expect(searchParams.body?.query).toEqual({ match: { field: 'value' } }); | ||
}); | ||
|
||
it('should call search with filters containing excluded data tiers', async () => { | ||
const excludedDataTiers = ['data_warm', 'data_cold']; | ||
uiSettingsClientMock.get.mockResolvedValue(excludedDataTiers); | ||
|
||
await performSearch(params); | ||
|
||
const searchParams = scopedClusterClientMock.asCurrentUser.search.mock | ||
.calls[0][0] as APMEventESSearchRequestParams; | ||
expect(searchParams.body?.query?.bool).toEqual({ | ||
must: [ | ||
{ match: { field: 'value' } }, | ||
{ bool: { must_not: [{ terms: { _tier: ['data_warm', 'data_cold'] } }] } }, | ||
], | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.