Skip to content

Commit

Permalink
feat(slo): Avoid false positive burn rate alerting with partial rolle…
Browse files Browse the repository at this point in the history
…d-up data (elastic#203279)
  • Loading branch information
kdelemme authored Jan 7, 2025
1 parent b302109 commit 0e13d86
Show file tree
Hide file tree
Showing 14 changed files with 167 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { SanitizedRuleConfig } from '@kbn/alerting-plugin/common';
import { Rule, SanitizedRuleConfig } from '@kbn/alerting-plugin/common';
import { DEFAULT_FLAPPING_SETTINGS } from '@kbn/alerting-plugin/common/rules_settings';
import { RuleExecutorServices } from '@kbn/alerting-plugin/server';
import { publicAlertsClientMock } from '@kbn/alerting-plugin/server/alerts_client/alerts_client.mock';
Expand All @@ -25,7 +25,13 @@ import {
import { ISearchStartSearchSource } from '@kbn/data-plugin/public';
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
import { MockedLogger } from '@kbn/logging-mocks';
import { Rule } from '@kbn/alerting-plugin/common';
import {
ALERT_EVALUATION_THRESHOLD,
ALERT_EVALUATION_VALUE,
ALERT_GROUP,
ALERT_REASON,
SLO_BURN_RATE_RULE_TYPE_ID,
} from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names';
import { SharePluginStart } from '@kbn/share-plugin/server';
import { sloDefinitionSchema } from '@kbn/slo-schema';
import { get } from 'lodash';
Expand All @@ -41,25 +47,18 @@ import {
SLO_INSTANCE_ID_FIELD,
SLO_REVISION_FIELD,
} from '../../../../common/field_names/slo';
import {
ALERT_EVALUATION_THRESHOLD,
ALERT_EVALUATION_VALUE,
ALERT_GROUP,
ALERT_REASON,
SLO_BURN_RATE_RULE_TYPE_ID,
} from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names';
import { SLODefinition, StoredSLODefinition } from '../../../domain/models';
import { SLONotFound } from '../../../errors';
import { SO_SLO_TYPE } from '../../../saved_objects';
import { createSLO } from '../../../services/fixtures/slo';
import { BurnRateAlert, getRuleExecutor } from './executor';
import {
LONG_WINDOW,
SHORT_WINDOW,
generateAboveThresholdKey,
generateBurnRateKey,
generateStatsKey,
generateWindowId,
LONG_WINDOW,
SHORT_WINDOW,
} from './lib/build_query';
import { EvaluationBucket } from './lib/evaluate';
import {
Expand Down Expand Up @@ -188,7 +187,7 @@ describe('BurnRateRuleExecutor', () => {
describe('multi-window', () => {
it('throws when the slo is not found', async () => {
soClientMock.find.mockRejectedValue(new SLONotFound('SLO [non-existent] not found'));
const executor = getRuleExecutor({ basePath: basePathMock });
const executor = getRuleExecutor(basePathMock);

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

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

const executor = getRuleExecutor({ basePath: basePathMock });
const executor = getRuleExecutor(basePathMock);
await executor({
params: ruleParams,
startedAt: new Date(),
Expand Down Expand Up @@ -312,7 +311,7 @@ describe('BurnRateRuleExecutor', () => {
generateEsResponse(ruleParams, [], { instanceId: 'bar' })
);

const executor = getRuleExecutor({ basePath: basePathMock });
const executor = getRuleExecutor(basePathMock);
await executor({
params: ruleParams,
startedAt: new Date(),
Expand Down Expand Up @@ -369,9 +368,7 @@ describe('BurnRateRuleExecutor', () => {
start: new Date().toISOString(),
}));

const executor = getRuleExecutor({
basePath: basePathMock,
});
const executor = getRuleExecutor(basePathMock);

await executor({
params: ruleParams,
Expand Down Expand Up @@ -519,9 +516,7 @@ describe('BurnRateRuleExecutor', () => {
start: new Date().toISOString(),
}));

const executor = getRuleExecutor({
basePath: basePathMock,
});
const executor = getRuleExecutor(basePathMock);

await executor({
params: ruleParams,
Expand Down Expand Up @@ -643,7 +638,7 @@ describe('BurnRateRuleExecutor', () => {
start: new Date().toISOString(),
}));

const executor = getRuleExecutor({ basePath: basePathMock });
const executor = getRuleExecutor(basePathMock);
await executor({
params: ruleParams,
startedAt: new Date(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,40 @@
* 2.0.
*/

import { i18n } from '@kbn/i18n';
import numeral from '@elastic/numeral';
import { AlertsClientError, ExecutorType, RuleExecutorOptions } from '@kbn/alerting-plugin/server';
import { ObservabilitySloAlert } from '@kbn/alerts-as-data-utils';
import { IBasePath } from '@kbn/core/server';
import { i18n } from '@kbn/i18n';
import { getEcsGroups } from '@kbn/observability-alerting-rule-utils';
import { getAlertDetailsUrl } from '@kbn/observability-plugin/common';
import {
ALERT_EVALUATION_THRESHOLD,
ALERT_EVALUATION_VALUE,
ALERT_GROUP,
ALERT_REASON,
} from '@kbn/rule-data-utils';
import { AlertsClientError, RuleExecutorOptions } from '@kbn/alerting-plugin/server';
import { IBasePath } from '@kbn/core/server';
import { LocatorPublic } from '@kbn/share-plugin/common';

import { upperCase } from 'lodash';
import { addSpaceIdToPath } from '@kbn/spaces-plugin/server';
import { ALL_VALUE } from '@kbn/slo-schema';
import { AlertsLocatorParams, getAlertDetailsUrl } from '@kbn/observability-plugin/common';
import { ObservabilitySloAlert } from '@kbn/alerts-as-data-utils';
import { ExecutorType } from '@kbn/alerting-plugin/server';
import { addSpaceIdToPath } from '@kbn/spaces-plugin/server';
import { upperCase } from 'lodash';
import {
ALERT_ACTION,
HIGH_PRIORITY_ACTION,
LOW_PRIORITY_ACTION,
MEDIUM_PRIORITY_ACTION,
SUPPRESSED_PRIORITY_ACTION,
} from '../../../../common/constants';
import {
SLO_ID_FIELD,
SLO_INSTANCE_ID_FIELD,
SLO_REVISION_FIELD,
} from '../../../../common/field_names/slo';
import { Duration } from '../../../domain/models';
import { KibanaSavedObjectsSLORepository } from '../../../services';
import { evaluate } from './lib/evaluate';
import { evaluateDependencies } from './lib/evaluate_dependencies';
import { shouldSuppressInstanceId } from './lib/should_suppress_instance_id';
import { getSloSummary } from './lib/summary_repository';
import {
AlertStates,
BurnRateAlertContext,
Expand All @@ -41,29 +49,12 @@ import {
Group,
WindowSchema,
} from './types';
import {
ALERT_ACTION,
HIGH_PRIORITY_ACTION,
MEDIUM_PRIORITY_ACTION,
LOW_PRIORITY_ACTION,
SUPPRESSED_PRIORITY_ACTION,
} from '../../../../common/constants';
import { evaluate } from './lib/evaluate';
import { evaluateDependencies } from './lib/evaluate_dependencies';
import { shouldSuppressInstanceId } from './lib/should_suppress_instance_id';
import { getSloSummary } from './lib/summary_repository';

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

export const getRuleExecutor = ({
basePath,
alertsLocator,
}: {
basePath: IBasePath;
alertsLocator?: LocatorPublic<AlertsLocatorParams>;
}) =>
export const getRuleExecutor = (basePath: IBasePath) =>
async function executor(
options: RuleExecutorOptions<
BurnRateRuleParams,
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ describe('buildQuery()', () => {
const rule = createBurnRateRule(slo);
expect(buildQuery(STARTED_AT, slo, rule)).toMatchSnapshot();
});

it('should return a valid query with afterKey', () => {
const slo = createSLO({
id: 'test-slo',
Expand All @@ -32,6 +33,7 @@ describe('buildQuery()', () => {
const rule = createBurnRateRule(slo);
expect(buildQuery(STARTED_AT, slo, rule, { instanceId: 'example' })).toMatchSnapshot();
});

it('should return a valid query for timeslices', () => {
const slo = createSLOWithTimeslicesBudgetingMethod({
id: 'test-slo',
Expand Down
Loading

0 comments on commit 0e13d86

Please sign in to comment.