Skip to content

Commit 0e13d86

Browse files
authored
feat(slo): Avoid false positive burn rate alerting with partial rolled-up data (#203279)
1 parent b302109 commit 0e13d86

File tree

14 files changed

+167
-101
lines changed

14 files changed

+167
-101
lines changed

x-pack/solutions/observability/plugins/slo/server/lib/rules/slo_burn_rate/executor.test.ts

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* 2.0.
66
*/
77

8-
import { SanitizedRuleConfig } from '@kbn/alerting-plugin/common';
8+
import { Rule, SanitizedRuleConfig } from '@kbn/alerting-plugin/common';
99
import { DEFAULT_FLAPPING_SETTINGS } from '@kbn/alerting-plugin/common/rules_settings';
1010
import { RuleExecutorServices } from '@kbn/alerting-plugin/server';
1111
import { publicAlertsClientMock } from '@kbn/alerting-plugin/server/alerts_client/alerts_client.mock';
@@ -25,7 +25,13 @@ import {
2525
import { ISearchStartSearchSource } from '@kbn/data-plugin/public';
2626
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
2727
import { MockedLogger } from '@kbn/logging-mocks';
28-
import { Rule } from '@kbn/alerting-plugin/common';
28+
import {
29+
ALERT_EVALUATION_THRESHOLD,
30+
ALERT_EVALUATION_VALUE,
31+
ALERT_GROUP,
32+
ALERT_REASON,
33+
SLO_BURN_RATE_RULE_TYPE_ID,
34+
} from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names';
2935
import { SharePluginStart } from '@kbn/share-plugin/server';
3036
import { sloDefinitionSchema } from '@kbn/slo-schema';
3137
import { get } from 'lodash';
@@ -41,25 +47,18 @@ import {
4147
SLO_INSTANCE_ID_FIELD,
4248
SLO_REVISION_FIELD,
4349
} from '../../../../common/field_names/slo';
44-
import {
45-
ALERT_EVALUATION_THRESHOLD,
46-
ALERT_EVALUATION_VALUE,
47-
ALERT_GROUP,
48-
ALERT_REASON,
49-
SLO_BURN_RATE_RULE_TYPE_ID,
50-
} from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names';
5150
import { SLODefinition, StoredSLODefinition } from '../../../domain/models';
5251
import { SLONotFound } from '../../../errors';
5352
import { SO_SLO_TYPE } from '../../../saved_objects';
5453
import { createSLO } from '../../../services/fixtures/slo';
5554
import { BurnRateAlert, getRuleExecutor } from './executor';
5655
import {
56+
LONG_WINDOW,
57+
SHORT_WINDOW,
5758
generateAboveThresholdKey,
5859
generateBurnRateKey,
5960
generateStatsKey,
6061
generateWindowId,
61-
LONG_WINDOW,
62-
SHORT_WINDOW,
6362
} from './lib/build_query';
6463
import { EvaluationBucket } from './lib/evaluate';
6564
import {
@@ -188,7 +187,7 @@ describe('BurnRateRuleExecutor', () => {
188187
describe('multi-window', () => {
189188
it('throws when the slo is not found', async () => {
190189
soClientMock.find.mockRejectedValue(new SLONotFound('SLO [non-existent] not found'));
191-
const executor = getRuleExecutor({ basePath: basePathMock });
190+
const executor = getRuleExecutor(basePathMock);
192191

193192
await expect(
194193
executor({
@@ -212,7 +211,7 @@ describe('BurnRateRuleExecutor', () => {
212211
it('returns early when the slo is disabled', async () => {
213212
const slo = createSLO({ objective: { target: 0.9 }, enabled: false });
214213
soClientMock.find.mockResolvedValueOnce(createFindResponse([slo]));
215-
const executor = getRuleExecutor({ basePath: basePathMock });
214+
const executor = getRuleExecutor(basePathMock);
216215

217216
const result = await executor({
218217
params: someRuleParamsWithWindows({ sloId: slo.id }),
@@ -264,7 +263,7 @@ describe('BurnRateRuleExecutor', () => {
264263
generateEsResponse(ruleParams, [], { instanceId: 'bar' })
265264
);
266265

267-
const executor = getRuleExecutor({ basePath: basePathMock });
266+
const executor = getRuleExecutor(basePathMock);
268267
await executor({
269268
params: ruleParams,
270269
startedAt: new Date(),
@@ -312,7 +311,7 @@ describe('BurnRateRuleExecutor', () => {
312311
generateEsResponse(ruleParams, [], { instanceId: 'bar' })
313312
);
314313

315-
const executor = getRuleExecutor({ basePath: basePathMock });
314+
const executor = getRuleExecutor(basePathMock);
316315
await executor({
317316
params: ruleParams,
318317
startedAt: new Date(),
@@ -369,9 +368,7 @@ describe('BurnRateRuleExecutor', () => {
369368
start: new Date().toISOString(),
370369
}));
371370

372-
const executor = getRuleExecutor({
373-
basePath: basePathMock,
374-
});
371+
const executor = getRuleExecutor(basePathMock);
375372

376373
await executor({
377374
params: ruleParams,
@@ -519,9 +516,7 @@ describe('BurnRateRuleExecutor', () => {
519516
start: new Date().toISOString(),
520517
}));
521518

522-
const executor = getRuleExecutor({
523-
basePath: basePathMock,
524-
});
519+
const executor = getRuleExecutor(basePathMock);
525520

526521
await executor({
527522
params: ruleParams,
@@ -643,7 +638,7 @@ describe('BurnRateRuleExecutor', () => {
643638
start: new Date().toISOString(),
644639
}));
645640

646-
const executor = getRuleExecutor({ basePath: basePathMock });
641+
const executor = getRuleExecutor(basePathMock);
647642
await executor({
648643
params: ruleParams,
649644
startedAt: new Date(),

x-pack/solutions/observability/plugins/slo/server/lib/rules/slo_burn_rate/executor.ts

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,40 @@
55
* 2.0.
66
*/
77

8-
import { i18n } from '@kbn/i18n';
98
import numeral from '@elastic/numeral';
9+
import { AlertsClientError, ExecutorType, RuleExecutorOptions } from '@kbn/alerting-plugin/server';
10+
import { ObservabilitySloAlert } from '@kbn/alerts-as-data-utils';
11+
import { IBasePath } from '@kbn/core/server';
12+
import { i18n } from '@kbn/i18n';
1013
import { getEcsGroups } from '@kbn/observability-alerting-rule-utils';
14+
import { getAlertDetailsUrl } from '@kbn/observability-plugin/common';
1115
import {
1216
ALERT_EVALUATION_THRESHOLD,
1317
ALERT_EVALUATION_VALUE,
1418
ALERT_GROUP,
1519
ALERT_REASON,
1620
} from '@kbn/rule-data-utils';
17-
import { AlertsClientError, RuleExecutorOptions } from '@kbn/alerting-plugin/server';
18-
import { IBasePath } from '@kbn/core/server';
19-
import { LocatorPublic } from '@kbn/share-plugin/common';
20-
21-
import { upperCase } from 'lodash';
22-
import { addSpaceIdToPath } from '@kbn/spaces-plugin/server';
2321
import { ALL_VALUE } from '@kbn/slo-schema';
24-
import { AlertsLocatorParams, getAlertDetailsUrl } from '@kbn/observability-plugin/common';
25-
import { ObservabilitySloAlert } from '@kbn/alerts-as-data-utils';
26-
import { ExecutorType } from '@kbn/alerting-plugin/server';
22+
import { addSpaceIdToPath } from '@kbn/spaces-plugin/server';
23+
import { upperCase } from 'lodash';
24+
import {
25+
ALERT_ACTION,
26+
HIGH_PRIORITY_ACTION,
27+
LOW_PRIORITY_ACTION,
28+
MEDIUM_PRIORITY_ACTION,
29+
SUPPRESSED_PRIORITY_ACTION,
30+
} from '../../../../common/constants';
2731
import {
2832
SLO_ID_FIELD,
2933
SLO_INSTANCE_ID_FIELD,
3034
SLO_REVISION_FIELD,
3135
} from '../../../../common/field_names/slo';
3236
import { Duration } from '../../../domain/models';
3337
import { KibanaSavedObjectsSLORepository } from '../../../services';
38+
import { evaluate } from './lib/evaluate';
39+
import { evaluateDependencies } from './lib/evaluate_dependencies';
40+
import { shouldSuppressInstanceId } from './lib/should_suppress_instance_id';
41+
import { getSloSummary } from './lib/summary_repository';
3442
import {
3543
AlertStates,
3644
BurnRateAlertContext,
@@ -41,29 +49,12 @@ import {
4149
Group,
4250
WindowSchema,
4351
} from './types';
44-
import {
45-
ALERT_ACTION,
46-
HIGH_PRIORITY_ACTION,
47-
MEDIUM_PRIORITY_ACTION,
48-
LOW_PRIORITY_ACTION,
49-
SUPPRESSED_PRIORITY_ACTION,
50-
} from '../../../../common/constants';
51-
import { evaluate } from './lib/evaluate';
52-
import { evaluateDependencies } from './lib/evaluate_dependencies';
53-
import { shouldSuppressInstanceId } from './lib/should_suppress_instance_id';
54-
import { getSloSummary } from './lib/summary_repository';
5552

5653
export type BurnRateAlert = Omit<ObservabilitySloAlert, 'kibana.alert.group'> & {
5754
[ALERT_GROUP]?: Group[];
5855
};
5956

60-
export const getRuleExecutor = ({
61-
basePath,
62-
alertsLocator,
63-
}: {
64-
basePath: IBasePath;
65-
alertsLocator?: LocatorPublic<AlertsLocatorParams>;
66-
}) =>
57+
export const getRuleExecutor = (basePath: IBasePath) =>
6758
async function executor(
6859
options: RuleExecutorOptions<
6960
BurnRateRuleParams,

x-pack/solutions/observability/plugins/slo/server/lib/rules/slo_burn_rate/lib/__snapshots__/build_query.test.ts.snap

Lines changed: 16 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x-pack/solutions/observability/plugins/slo/server/lib/rules/slo_burn_rate/lib/build_query.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ describe('buildQuery()', () => {
2424
const rule = createBurnRateRule(slo);
2525
expect(buildQuery(STARTED_AT, slo, rule)).toMatchSnapshot();
2626
});
27+
2728
it('should return a valid query with afterKey', () => {
2829
const slo = createSLO({
2930
id: 'test-slo',
@@ -32,6 +33,7 @@ describe('buildQuery()', () => {
3233
const rule = createBurnRateRule(slo);
3334
expect(buildQuery(STARTED_AT, slo, rule, { instanceId: 'example' })).toMatchSnapshot();
3435
});
36+
3537
it('should return a valid query for timeslices', () => {
3638
const slo = createSLOWithTimeslicesBudgetingMethod({
3739
id: 'test-slo',

0 commit comments

Comments
 (0)