[8.10] [DOCS] Automate screenshots for Elasticsearch query rule actions (#164794) (#166018)

# Backport

This will backport the following commits from `main` to `8.10`:
- [[DOCS] Automate screenshots for Elasticsearch query rule actions
(#164794)](https://github.com/elastic/kibana/pull/164794)

<!--- Backport version: 8.9.7 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Lisa
Cawley","email":"lcawley@elastic.co"},"sourceCommit":{"committedDate":"2023-09-07T19:16:10Z","message":"[DOCS]
Automate screenshots for Elasticsearch query rule actions
(#164794)","sha":"3151aad37bf42b91358dad02cd4a16a485004c73","branchLabelMapping":{"^v8.11.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Feature:Alerting","release_note:skip","Team:ResponseOps","docs","v8.10.0","v8.11.0"],"number":164794,"url":"https://github.com/elastic/kibana/pull/164794","mergeCommit":{"message":"[DOCS]
Automate screenshots for Elasticsearch query rule actions
(#164794)","sha":"3151aad37bf42b91358dad02cd4a16a485004c73"}},"sourceBranch":"main","suggestedTargetBranches":["8.10"],"targetPullRequestStates":[{"branch":"8.10","label":"v8.10.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.11.0","labelRegex":"^v8.11.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/164794","number":164794,"mergeCommit":{"message":"[DOCS]
Automate screenshots for Elasticsearch query rule actions
(#164794)","sha":"3151aad37bf42b91358dad02cd4a16a485004c73"}}]}]
BACKPORT-->

Co-authored-by: Lisa Cawley <lcawley@elastic.co>
This commit is contained in:
Kibana Machine 2023-09-07 16:47:12 -04:00 committed by GitHub
parent d203740ef3
commit 552cb18318
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 202 additions and 151 deletions

View file

@ -1,4 +1,3 @@
[role="xpack"]
[[create-and-manage-rules]]
== Create and manage rules
:frontmatter-description: Set up alerting in the {kib} {stack-manage-app} app and manage your rules.
@ -52,10 +51,11 @@ For more details, refer to the https://registry.terraform.io/providers/elastic/e
Depending on the {kib} app and context, you might be prompted to choose the type of rule to create. Some apps will preselect the type of rule for you.
Each rule type provides its own way of defining the conditions to detect, but an expression formed by a series of clauses is a common pattern. For example, in a metric threshold rule, the `WHEN` clause enables you to select an aggregation operation to apply to a numeric field.
Each rule type provides its own way of defining the conditions to detect, but an expression formed by a series of clauses is a common pattern.
For example, in an {es} query rule, you specify an index, a query, and a threshold, which uses a metric aggregation operation (`count`, `average`, `max`, `min`, or `sum`):
[role="screenshot"]
image::images/rule-flyout-rule-conditions.png[UI for defining rule conditions on a metric threshold rule,500]
image::images/es-query-rule-conditions.png[UI for defining rule conditions in an {es} query rule,500]
// NOTE: This is an autogenerated screenshot. Do not edit it directly.
All rules must have a check interval, which defines how often to evaluate the rule conditions. Checks are queued; they run as close to the defined value as capacity allows.
@ -71,15 +71,16 @@ conditions are met and when they are no longer met.
Each action uses a connector, which provides connection information for a {kib} service or third party integration, depending on where you want to send the notifications. If no connectors exist, click **Add connector** to create one.
After you select a connector, set the action frequency. If the rule type supports alert summaries, you can choose to create a summary of alerts on each check interval or on a custom interval. For example, if you create a metrics threshold rule, you can send email notifications that summarize the new, ongoing, and recovered alerts each hour:
After you select a connector, set the action frequency. If the rule type supports alert summaries, you can choose to create a summary of alerts on each check interval or on a custom interval.
For example, if you create an {es} query rule, you can send notifications that summarize the new, ongoing, and recovered alerts on a custom interval:
[role="screenshot"]
image::images/action-alert-summary.png[UI for defining rule conditions on a metric threshold rule,500]
image::images/es-query-rule-action-summary.png[UI for defining alert summary action in an {es} query rule,500]
// NOTE: This is an autogenerated screenshot. Do not edit it directly.
[NOTE]
====
* The rules that support alert summaries, such as this metric threshold rule, enable you to further refine when actions run by adding time frame and query filters.
* Some rules that support alert summaries, such as metric threshold rules, enable you to further refine when actions run by adding time frame and query filters.
* If you choose a custom action interval, it cannot be shorter than the rule's check interval.
====
@ -87,10 +88,10 @@ Alternatively, you can set the action frequency such that the action runs for ea
If the rule type does not support alert summaries, this is your only available option.
You must choose when the action runs (for example, at each check interval, only when the alert status changes, or at a custom action interval).
You must also choose an action group, which affects whether the action runs. Each rule type has a specific set of valid action groups.
For example, you can set *Run when* to `Alert`, `Warning`, `No data`, or `Recovered` for the metric threshold rule:
For example, you can set *Run when* to `Query matched` or `Recovered` for the {es} query rule:
[role="screenshot"]
image::images/rule-flyout-action-details.png[UI for defining an email action,500]
image::images/es-query-rule-recovery-action.png[UI for defining a recovery action,500]
// NOTE: This is an autogenerated screenshot. Do not edit it directly.
Each connector enables different action properties. For example, an email connector enables you to set the recipients, the subject, and a message body in markdown format. For more information about connectors, refer to <<action-types>>.
@ -123,7 +124,7 @@ You can pass rule values to an action at the time a condition is detected.
To view the list of variables available for your rule, click the "add rule variable" button:
[role="screenshot"]
image::images/rule-flyout-action-variables.png[Passing rule values to an action,500]
image::images/es-query-rule-action-variables.png[Passing rule values to an action,500]
// NOTE: This is an autogenerated screenshot. Do not edit it directly.
For more information about common action variables, refer to <<rule-action-variables>>.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

View file

@ -1,7 +1,7 @@
[[rule-type-es-query]]
== {es} query
:frontmatter-description: An {es} query rule generates alerts when your query meets a threshold.
:frontmatter-description: Create an {es} query rule, which generates alerts when your query meets a threshold.
:frontmatter-tags-products: [kibana,alerting]
:frontmatter-tags-content-type: [overview]
:frontmatter-tags-user-goals: [analyze]
@ -10,18 +10,15 @@ The {es} query rule type runs a user-configured query, compares the number of
matches to a configured threshold, and schedules actions to run when the
threshold condition is met.
[float]
=== Create the rule
Fill in the name and optional tags, then select
*{es} query*. {es} query rule can be defined using KQL/Lucene or Query DSL.
In *{stack-manage-app}* > *{rules-ui}*, click *Create rule*, fill in the name and optional tags, then select *{es} query*.
An {es} query rule can be defined using KQL/Lucene or Query DSL.
[float]
=== Define the conditions
Define properties to detect the condition.
[role="screenshot"]
image::user/alerting/images/rule-types-es-query-conditions.png[Define the condition to detect]
// NOTE: This is an autogenerated screenshot. Do not edit it directly.
@ -46,13 +43,48 @@ Exclude matches from previous run:: Turn on to avoid alert duplication by
excluding documents that have already been detected by the previous rule run. This
option is not available when a grouping field is specified.
[float]
=== Add actions
You can optionally send notifications when the rule conditions are met and when they are no longer met.
In particular, this rule type supports:
* alert summaries
* actions that run when the query is matched
* recovery actions that run when the rule conditions are no longer met
For each action, you must choose a connector, which provides connection information for a {kib} service or third party integration. For more information about all the supported connectors, go to <<action-types>>.
After you select a connector, you must set the action frequency.
You can choose to create a summary of alerts on each check interval or on a custom interval.
For example, send email notifications that summarize the new, ongoing, and recovered alerts at a custom interval:
[role="screenshot"]
image::images/es-query-rule-action-summary.png[UI for defining alert summary action in an {es} query rule]
// NOTE: This is an autogenerated screenshot. Do not edit it directly.
Alternatively, you can set the action frequency such that actions run for each alert.
Choose how often the action runs (at each check interval, only when the alert status changes, or at a custom action interval).
You must also choose an action group, which indicates whether the action runs when the query is matched or when the alert is recovered.
For example:
[role="screenshot"]
image::images/es-query-rule-action-query-matched.png[UI for defining a recovery action]
// NOTE: This is an autogenerated screenshot. Do not edit it directly.
[float]
=== Add action variables
<<defining-rules-actions-details, Add an action>> to run when the rule condition
is met. The following variables are specific to the {es} query rule. You can
also specify
<<defining-rules-actions-variables, variables common to all rules>>.
You can pass rule values to an action to provide contextual details.
To view the list of variables available for each action, click the "add rule variable" button.
For example:
[role="screenshot"]
image::images/es-query-rule-action-variables.png[Passing rule values to an action]
// NOTE: This is an autogenerated screenshot. Do not edit it directly.
The following variables are specific to the {es} query rule.
You can also specify <<defining-rules-actions-variables,variables common to all rules>>.
`context.title`:: A preconstructed title for the rule. Example:
`rule term match alert query matched`.
@ -76,17 +108,26 @@ Example: `2022-02-03T20:29:27.732Z`.
`context.hits`:: The most recent documents that matched the query. Using the
https://mustache.github.io/[Mustache] template array syntax, you can iterate
over these hits to get values from the ES documents into your actions.
+
[role="screenshot"]
image::images/rule-types-es-query-example-action-variable.png[Iterate over hits using Mustache template syntax]
+
The documents returned by `context.hits` include the {ref}/mapping-source-field.html[`_source`] field.
If the {es} query search API's {ref}/search-fields.html#search-fields-param[`fields`] parameter is used, documents will also return the `fields` field,
which can be used to access any runtime fields defined by the {ref}/runtime-search-request.html[`runtime_mappings`] parameter as the following example shows:
over these hits to get values from the {es} documents into your actions.
For example, the message in an email connector action might contain:
+
--
[source]
[source,sh]
--------------------------------------------------
Elasticsearch query rule '{{rule.name}}' is active:
{{#context.hits}}
Document with {{_id}} and hostname {{_source.host.name}} has
{{_source.system.memory.actual.free}} bytes of memory free
{{/context.hits}}
--------------------------------------------------
The documents returned by `context.hits` include the {ref}/mapping-source-field.html[`_source`] field.
If the {es} query search API's {ref}/search-fields.html#search-fields-param[`fields`] parameter is used, documents will also return the `fields` field,
which can be used to access any runtime fields defined by the {ref}/runtime-search-request.html[`runtime_mappings`] parameter.
For example:
[source,sh]
--------------------------------------------------
{{#context.hits}}
timestamp: {{_source.@timestamp}}
@ -95,13 +136,12 @@ day of the week: {{fields.day_of_week}} <1>
--------------------------------------------------
// NOTCONSOLE
<1> The `fields` parameter here is used to access the `day_of_week` runtime field.
--
+
As the {ref}/search-fields.html#search-fields-response[`fields`] response always returns an array of values for each field,
the https://mustache.github.io/[Mustache] template array syntax is used to iterate over these values in your actions as the following example shows:
+
--
[source]
the https://mustache.github.io/[Mustache] template array syntax is used to iterate over these values in your actions.
For example:
[source,sh]
--------------------------------------------------
{{#context.hits}}
Labels:

View file

@ -6,6 +6,7 @@
*/
import { FtrProviderContext } from '../../../ftr_provider_context';
import { esQueryRuleName } from '.';
export default function ({ getService, getPageObjects }: FtrProviderContext) {
const browser = getService('browser');
@ -106,7 +107,63 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
1400,
1500
);
// Create an email connector action
await testSubjects.click('.email-alerting-ActionTypeSelectOption');
await testSubjects.scrollIntoView('addAlertActionButton');
await commonScreenshots.takeScreenshot(
'es-query-rule-action-query-matched',
screenshotDirectories,
1400,
1024
);
await testSubjects.click('messageAddVariableButton');
await commonScreenshots.takeScreenshot(
'es-query-rule-action-variables',
screenshotDirectories,
1400,
1024
);
await browser.pressKeys(browser.keys.ESCAPE);
await testSubjects.click('cancelSaveRuleButton');
});
it('example elasticsearch query rule conditions and actions', async () => {
await pageObjects.common.navigateToApp('triggersActions');
await pageObjects.header.waitUntilLoadingHasFinished();
// Edit the rule that was created as part of startup
await testSubjects.setValue('ruleSearchField', esQueryRuleName);
await browser.pressKeys(browser.keys.ENTER);
const actionPanel = await testSubjects.find('collapsedItemActions');
await actionPanel.click();
const editRuleMenu = await testSubjects.find('editRule');
await editRuleMenu.click();
await pageObjects.header.waitUntilLoadingHasFinished();
await commonScreenshots.takeScreenshot(
'es-query-rule-conditions',
screenshotDirectories,
1400,
1700
);
/* Reposition so that the details are visible for the first action */
await testSubjects.scrollIntoView('alertActionAccordion-0');
await commonScreenshots.takeScreenshot(
'es-query-rule-action-summary',
screenshotDirectories,
1400,
1024
);
/* Reposition so that the details are visible for the second action */
await testSubjects.scrollIntoView('alertActionAccordion-1');
await commonScreenshots.takeScreenshot(
'es-query-rule-recovery-action',
screenshotDirectories,
1400,
1024
);
const cancelEditButton = await testSubjects.find('cancelSaveEditedRuleButton');
await cancelEditButton.click();
const confirmCancelButton = await testSubjects.find('confirmModalConfirmButton');
await confirmCancelButton.click();
});
});
}

View file

@ -8,18 +8,34 @@
import { FtrProviderContext } from '../../../ftr_provider_context';
export const indexThresholdRuleName = 'kibana sites - low bytes';
export const metricThresholdRuleName = 'network metric packets';
export const esQueryRuleName = 'sample logs query rule';
export default function ({ loadTestFile, getService }: FtrProviderContext) {
const browser = getService('browser');
const actions = getService('actions');
const rules = getService('rules');
const emailConnectorName = 'Email connector 1';
const validQueryJson = JSON.stringify({
query: {
bool: {
filter: [
{
term: {
'host.keyword': 'www.elastic.co',
},
},
],
},
},
});
describe('stack alerting', function () {
let itRuleId: string;
let mtRuleId: string;
let esRuleId: string;
let serverLogConnectorId: string;
let emailConnectorId: string;
before(async () => {
// Create server log connector
await browser.setWindowSize(1920, 1080);
({ id: serverLogConnectorId } = await actions.api.createConnector({
name: 'my-server-log-connector',
@ -27,6 +43,22 @@ export default function ({ loadTestFile, getService }: FtrProviderContext) {
secrets: {},
connectorTypeId: '.server-log',
}));
// Create email connector
({ id: emailConnectorId } = await actions.api.createConnector({
name: emailConnectorName,
config: {
service: 'other',
from: 'bob@example.com',
host: 'some.non.existent.com',
port: 25,
},
secrets: {
user: 'bob',
password: 'supersecret',
},
connectorTypeId: '.email',
}));
// Create index threshold rule
({ id: itRuleId } = await rules.api.createRule({
consumer: 'alerts',
name: indexThresholdRuleName,
@ -57,35 +89,48 @@ export default function ({ loadTestFile, getService }: FtrProviderContext) {
},
],
}));
({ id: mtRuleId } = await rules.api.createRule({
consumer: 'infrastructure',
name: metricThresholdRuleName,
notifyWhen: 'onActionGroupChange',
// Create Elasticsearch query rule
({ id: esRuleId } = await rules.api.createRule({
consumer: 'alerts',
name: esQueryRuleName,
params: {
criteria: [
{
aggType: 'max',
comparator: '>',
threshold: [0],
timeSize: 3,
timeUnit: 's',
metric: 'network.packets',
},
],
sourceId: 'default',
alertOnNoData: false,
alertOnGroupDisappear: false,
groupBy: ['network.name'],
index: ['kibana_sample_data_logs'],
timeField: '@timestamp',
timeWindowSize: 1,
timeWindowUnit: 'd',
thresholdComparator: '>',
threshold: [100],
size: 100,
esQuery: validQueryJson,
},
ruleTypeId: 'metrics.alert.threshold',
schedule: { interval: '1m' },
ruleTypeId: '.es-query',
schedule: { interval: '1d' },
actions: [
{
group: 'metrics.threshold.fired',
group: 'query matched',
id: emailConnectorId,
frequency: {
throttle: '2d',
summary: true,
notify_when: 'onThrottleInterval',
},
params: {
to: ['test@example.com'],
subject: 'Alert summary',
message:
'The system has detected {{alerts.new.count}} new, {{alerts.ongoing.count}} ongoing, and {{alerts.recovered.count}} recovered alerts.',
},
},
{
group: 'recovered',
id: serverLogConnectorId,
frequency: {
summary: false,
notify_when: 'onActionGroupChange',
},
params: {
level: 'info',
message: 'Test Metric Threshold rule',
message: '{{alert.id}} has recovered.',
},
},
],
@ -94,7 +139,7 @@ export default function ({ loadTestFile, getService }: FtrProviderContext) {
after(async () => {
await rules.api.deleteRule(itRuleId);
await rules.api.deleteRule(mtRuleId);
await rules.api.deleteRule(esRuleId);
await rules.api.deleteAllRules();
await actions.api.deleteConnector(serverLogConnectorId);
await actions.api.deleteAllConnectors();
@ -103,7 +148,6 @@ export default function ({ loadTestFile, getService }: FtrProviderContext) {
loadTestFile(require.resolve('./es_query_rule'));
loadTestFile(require.resolve('./index_threshold_rule'));
loadTestFile(require.resolve('./list_view'));
loadTestFile(require.resolve('./metrics_threshold_rule'));
loadTestFile(require.resolve('./tracking_containment_rule'));
});
}

View file

@ -1,91 +0,0 @@
/*
* 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 { FtrProviderContext } from '../../../ftr_provider_context';
import { metricThresholdRuleName } from '.';
export default function ({ getService, getPageObjects }: FtrProviderContext) {
const actions = getService('actions');
const browser = getService('browser');
const commonScreenshots = getService('commonScreenshots');
const testSubjects = getService('testSubjects');
const pageObjects = getPageObjects(['common', 'header']);
const screenshotDirectories = ['response_ops_docs', 'stack_alerting'];
const emailConnectorName = 'Email connector 1';
describe('metric threshold rule', function () {
let emailConnectorId: string;
before(async () => {
({ id: emailConnectorId } = await actions.api.createConnector({
name: emailConnectorName,
config: {
service: 'other',
from: 'bob@example.com',
host: 'some.non.existent.com',
port: 25,
},
secrets: {
user: 'bob',
password: 'supersecret',
},
connectorTypeId: '.email',
}));
});
after(async () => {
await actions.api.deleteConnector(emailConnectorId);
});
it('example metric threshold rule conditions and actions', async () => {
await pageObjects.common.navigateToApp('triggersActions');
await pageObjects.header.waitUntilLoadingHasFinished();
await testSubjects.setValue('ruleSearchField', metricThresholdRuleName);
await browser.pressKeys(browser.keys.ENTER);
const actionPanel = await testSubjects.find('collapsedItemActions');
await actionPanel.click();
const editRuleMenu = await testSubjects.find('editRule');
await editRuleMenu.click();
const expandExpression = await testSubjects.find('expandRow');
await expandExpression.click();
await pageObjects.header.waitUntilLoadingHasFinished();
await commonScreenshots.takeScreenshot(
'rule-flyout-rule-conditions',
screenshotDirectories,
1400,
1500
);
const serverLogAction = await testSubjects.find('alertActionAccordion-0');
const removeConnectorButton = await serverLogAction.findByCssSelector(
'[aria-label="Delete"]'
);
await removeConnectorButton.click();
await testSubjects.click('.email-alerting-ActionTypeSelectOption');
await testSubjects.scrollIntoView('addAlertActionButton');
await commonScreenshots.takeScreenshot(
'rule-flyout-action-details',
screenshotDirectories,
1400,
1024
);
await testSubjects.scrollIntoView('addAlertActionButton');
await testSubjects.click('messageAddVariableButton');
await commonScreenshots.takeScreenshot(
'rule-flyout-action-variables',
screenshotDirectories,
1400,
1024
);
const cancelEditButton = await testSubjects.find('cancelSaveEditedRuleButton');
await cancelEditButton.click();
const confirmCancelButton = await testSubjects.find('confirmModalConfirmButton');
await confirmCancelButton.click();
});
});
}