diff --git a/docs/user/alerting/rule-types/es-query.asciidoc b/docs/user/alerting/rule-types/es-query.asciidoc index 715fabc6fdc38..c838200e637e1 100644 --- a/docs/user/alerting/rule-types/es-query.asciidoc +++ b/docs/user/alerting/rule-types/es-query.asciidoc @@ -26,7 +26,7 @@ the *time window*. Size:: Specifies the number of documents to pass to the configured actions when the threshold condition is met. {es} query:: Specifies the ES DSL query. The number of documents that -match this query is evaluated against the threshold condition. Only the `query`, `fields` and `runtime_mappings` +match this query is evaluated against the threshold condition. Only the `query`, `fields`, `_source` and `runtime_mappings` fields are used, other DSL fields are not considered. Threshold:: Defines a threshold value and a comparison operator (`is above`, `is above or equals`, `is below`, `is below or equals`, or `is between`). The diff --git a/x-pack/plugins/stack_alerts/common/build_sorted_events_query.ts b/x-pack/plugins/stack_alerts/common/build_sorted_events_query.ts index aaa5addcc6358..159576fa10dce 100644 --- a/x-pack/plugins/stack_alerts/common/build_sorted_events_query.ts +++ b/x-pack/plugins/stack_alerts/common/build_sorted_events_query.ts @@ -23,6 +23,7 @@ export interface BuildSortedEventsQuery extends BuildSortedEventsQueryOpts { timeField: string; fields?: string[]; runtime_mappings?: unknown; + _source?: unknown; } export const buildSortedEventsQuery = ({ @@ -40,6 +41,7 @@ export const buildSortedEventsQuery = ({ fields, // eslint-disable-next-line @typescript-eslint/naming-convention runtime_mappings, + _source, }: BuildSortedEventsQuery): ESSearchRequest => { const sortField = timeField; const docFields = [timeField].map((tstamp) => ({ @@ -89,6 +91,7 @@ export const buildSortedEventsQuery = ({ }, ...(runtime_mappings ? { runtime_mappings } : {}), ...(fields ? { fields } : {}), + ...(_source != null ? { _source } : {}), }; if (searchAfterSortId) { diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/lib/fetch_es_query.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/lib/fetch_es_query.ts index d6f373feb65f6..3e94745d295fb 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/lib/fetch_es_query.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/lib/fetch_es_query.ts @@ -28,7 +28,7 @@ export async function fetchEsQuery( const esClient = scopedClusterClient.asCurrentUser; const { // eslint-disable-next-line @typescript-eslint/naming-convention - parsedQuery: { query, fields, runtime_mappings }, + parsedQuery: { query, fields, runtime_mappings, _source }, dateStart, dateEnd, } = getSearchParams(params); @@ -76,6 +76,7 @@ export async function fetchEsQuery( track_total_hits: true, fields, runtime_mappings, + _source, }); logger.debug( diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/index.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/index.ts index 8f10635975ba0..98c0737ba670c 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/index.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/index.ts @@ -11,5 +11,6 @@ import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; export default function alertingTests({ loadTestFile }: FtrProviderContext) { describe('es_query', () => { loadTestFile(require.resolve('./rule')); + loadTestFile(require.resolve('./query_dsl_only')); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/query_dsl_only.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/query_dsl_only.ts index 1f7930fc1bac4..9ba78b31ea5ec 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/query_dsl_only.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/query_dsl_only.ts @@ -159,7 +159,7 @@ export default function ruleTests({ getService }: FtrProviderContext) { "fields": [ { "field": "@timestamp", - "format": "epoch_millis" + "format": "epoch_millis" } ], "query": { @@ -190,6 +190,73 @@ export default function ruleTests({ getService }: FtrProviderContext) { } }); + it(`runs correctly: _source: false field for esQuery search type`, async () => { + // write documents from now to the future end date in groups + await createEsDocumentsInGroups(ES_GROUPS_TO_WRITE, endDate); + await createRule({ + name: 'always fire', + esQuery: ` + { + "query": { + "match_all": { } + }, + "_source": false + }`.replace(`"`, `\"`), + size: 100, + thresholdComparator: '>', + threshold: [-1], + }); + + const docs = await waitForDocs(2); + for (let i = 0; i < docs.length; i++) { + const doc = docs[i]; + const { name, title } = doc._source.params; + expect(name).to.be('always fire'); + expect(title).to.be(`rule 'always fire' matched query`); + + const hits = JSON.parse(doc._source.hits); + expect(hits).not.to.be.empty(); + hits.forEach((hit: any) => { + expect(hit._source).to.be(undefined); + }); + } + }); + + it(`runs correctly: _source field for esQuery search type`, async () => { + // write documents from now to the future end date in groups + await createEsDocumentsInGroups(ES_GROUPS_TO_WRITE, endDate); + await createRule({ + name: 'always fire', + esQuery: ` + { + "query": { + "match_all": { } + }, + "_source": "testedValue*" + }`.replace(`"`, `\"`), + size: 100, + thresholdComparator: '>', + threshold: [-1], + }); + + const docs = await waitForDocs(2); + for (let i = 0; i < docs.length; i++) { + const doc = docs[i]; + const { name, title } = doc._source.params; + expect(name).to.be('always fire'); + expect(title).to.be(`rule 'always fire' matched query`); + + const hits = JSON.parse(doc._source.hits); + expect(hits).not.to.be.empty(); + hits.forEach((hit: any) => { + expect(hit._source).not.to.be.empty(); + Object.keys(hit._source).forEach((key) => { + expect(key.startsWith('testedValue')).to.be(true); + }); + }); + } + }); + async function createRule(params: CreateRuleParams): Promise { const action = { id: connectorId,