mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[SLO]: Limit initial data backfill for SLO for serverless (#208790)
Resolves #188428 ## Summary - Add callout in serverless to indicate that initial data backfill is limited to 7 days. - If prevent data backfill is checked, transform will still use the SLO delay for the filter range. - If serverless and prevent data backfill is not checked, data backfill is hard coded to 7 days, the lowest rolling time window option. Time window will not be rounded down. <img width="980" alt="Screenshot 2025-01-29 at 11 18 01 AM" src="https://github.com/user-attachments/assets/b6481ef9-cc0e-4403-8309-50b6d8f37e70" />
This commit is contained in:
parent
b53d3990a2
commit
ee14e50fe1
19 changed files with 129 additions and 54 deletions
|
@ -32,6 +32,7 @@ import { CreateSLOForm } from '../types';
|
|||
import { MAX_WIDTH } from '../constants';
|
||||
import { AdvancedSettings } from './indicator_section/advanced_settings/advanced_settings';
|
||||
import { SloEditFormObjectiveSectionTimeslices } from './slo_edit_form_objective_section_timeslices';
|
||||
import { usePluginContext } from '../../../hooks/use_plugin_context';
|
||||
|
||||
export function SloEditFormObjectiveSection() {
|
||||
const {
|
||||
|
@ -41,6 +42,8 @@ export function SloEditFormObjectiveSection() {
|
|||
setValue,
|
||||
formState: { defaultValues },
|
||||
} = useFormContext<CreateSLOForm>();
|
||||
const { isServerless } = usePluginContext();
|
||||
|
||||
const budgetingSelect = useGeneratedHtmlId({ prefix: 'budgetingSelect' });
|
||||
const timeWindowTypeSelect = useGeneratedHtmlId({ prefix: 'timeWindowTypeSelect' });
|
||||
const timeWindowSelect = useGeneratedHtmlId({ prefix: 'timeWindowSelect' });
|
||||
|
@ -94,6 +97,13 @@ export function SloEditFormObjectiveSection() {
|
|||
data-test-subj="sloEditFormObjectiveSection"
|
||||
>
|
||||
<EuiFlexGroup direction="column" gutterSize="m">
|
||||
{isServerless && (
|
||||
<EuiCallOut>
|
||||
{i18n.translate('xpack.slo.sloEdit.timeWindow.serverlessWarning', {
|
||||
defaultMessage: 'Initial data backfill is limited to the past 7 days',
|
||||
})}
|
||||
</EuiCallOut>
|
||||
)}
|
||||
<EuiFlexGrid columns={3} gutterSize="m">
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
import { ApmTransactionDurationTransformGenerator } from './apm_transaction_duration';
|
||||
|
||||
const SPACE_ID = 'custom-space';
|
||||
const generator = new ApmTransactionDurationTransformGenerator(SPACE_ID, dataViewsService);
|
||||
const generator = new ApmTransactionDurationTransformGenerator(SPACE_ID, dataViewsService, false);
|
||||
|
||||
describe('APM Transaction Duration Transform Generator', () => {
|
||||
it('returns the expected transform params with every specified indicator params', async () => {
|
||||
|
|
|
@ -26,8 +26,8 @@ import { InvalidTransformError } from '../../errors';
|
|||
import { getFilterRange, getTimesliceTargetComparator, parseIndex } from './common';
|
||||
|
||||
export class ApmTransactionDurationTransformGenerator extends TransformGenerator {
|
||||
constructor(spaceId: string, dataViewService: DataViewsService) {
|
||||
super(spaceId, dataViewService);
|
||||
constructor(spaceId: string, dataViewService: DataViewsService, isServerless: boolean) {
|
||||
super(spaceId, dataViewService, isServerless);
|
||||
}
|
||||
|
||||
public async getTransformParams(slo: SLODefinition): Promise<TransformPutTransformRequest> {
|
||||
|
@ -75,7 +75,9 @@ export class ApmTransactionDurationTransformGenerator extends TransformGenerator
|
|||
}
|
||||
|
||||
private async buildSource(slo: SLODefinition, indicator: APMTransactionDurationIndicator) {
|
||||
const queryFilter: estypes.QueryDslQueryContainer[] = [getFilterRange(slo, '@timestamp')];
|
||||
const queryFilter: estypes.QueryDslQueryContainer[] = [
|
||||
getFilterRange(slo, '@timestamp', this.isServerless),
|
||||
];
|
||||
|
||||
if (indicator.params.service !== ALL_VALUE) {
|
||||
queryFilter.push({
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
import { ApmTransactionErrorRateTransformGenerator } from './apm_transaction_error_rate';
|
||||
|
||||
const SPACE_ID = 'custom-space';
|
||||
const generator = new ApmTransactionErrorRateTransformGenerator(SPACE_ID, dataViewsService);
|
||||
const generator = new ApmTransactionErrorRateTransformGenerator(SPACE_ID, dataViewsService, false);
|
||||
|
||||
describe('APM Transaction Error Rate Transform Generator', () => {
|
||||
it('returns the expected transform params with every specified indicator params', async () => {
|
||||
|
|
|
@ -25,8 +25,8 @@ import { InvalidTransformError } from '../../errors';
|
|||
import { getFilterRange, getTimesliceTargetComparator, parseIndex } from './common';
|
||||
|
||||
export class ApmTransactionErrorRateTransformGenerator extends TransformGenerator {
|
||||
constructor(spaceId: string, dataViewService: DataViewsService) {
|
||||
super(spaceId, dataViewService);
|
||||
constructor(spaceId: string, dataViewService: DataViewsService, isServerless: boolean) {
|
||||
super(spaceId, dataViewService, isServerless);
|
||||
}
|
||||
|
||||
public async getTransformParams(slo: SLODefinition): Promise<TransformPutTransformRequest> {
|
||||
|
@ -74,7 +74,9 @@ export class ApmTransactionErrorRateTransformGenerator extends TransformGenerato
|
|||
}
|
||||
|
||||
private async buildSource(slo: SLODefinition, indicator: APMTransactionErrorRateIndicator) {
|
||||
const queryFilter: estypes.QueryDslQueryContainer[] = [getFilterRange(slo, '@timestamp')];
|
||||
const queryFilter: estypes.QueryDslQueryContainer[] = [
|
||||
getFilterRange(slo, '@timestamp', this.isServerless),
|
||||
];
|
||||
|
||||
if (indicator.params.service !== ALL_VALUE) {
|
||||
queryFilter.push({
|
||||
|
|
|
@ -45,7 +45,8 @@ describe('common', () => {
|
|||
preventInitialBackfill: true,
|
||||
},
|
||||
}),
|
||||
'@timestamp'
|
||||
'@timestamp',
|
||||
false
|
||||
)
|
||||
).toEqual({
|
||||
range: {
|
||||
|
@ -67,7 +68,8 @@ describe('common', () => {
|
|||
preventInitialBackfill: false,
|
||||
},
|
||||
}),
|
||||
'@timestamp'
|
||||
'@timestamp',
|
||||
false
|
||||
)
|
||||
).toEqual({
|
||||
range: {
|
||||
|
@ -77,5 +79,28 @@ describe('common', () => {
|
|||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('starts at now minus 7 days when preventInitialBackfill is false and serverless is true', () => {
|
||||
expect(
|
||||
getFilterRange(
|
||||
createSLO({
|
||||
timeWindow: thirtyDaysRolling(),
|
||||
settings: {
|
||||
frequency: twoMinute(),
|
||||
syncDelay: fiveMinute(),
|
||||
preventInitialBackfill: false,
|
||||
},
|
||||
}),
|
||||
'@timestamp',
|
||||
true
|
||||
)
|
||||
).toEqual({
|
||||
range: {
|
||||
'@timestamp': {
|
||||
gte: 'now-7d',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -61,20 +61,32 @@ export function getTimesliceTargetComparator(timesliceTarget: number) {
|
|||
* preventInitialBackfill == true: we use the current time minus some buffer to account for the ingestion delay
|
||||
* preventInitialBackfill === false: we use the time window duration to get the data for the last N days
|
||||
*/
|
||||
export function getFilterRange(slo: SLODefinition, timestampField: string) {
|
||||
return slo.settings.preventInitialBackfill === true
|
||||
? {
|
||||
range: {
|
||||
[timestampField]: {
|
||||
gte: `now-${getDelayInSecondsFromSLO(slo)}s/m`,
|
||||
},
|
||||
export function getFilterRange(slo: SLODefinition, timestampField: string, isServerless: boolean) {
|
||||
if (slo.settings.preventInitialBackfill) {
|
||||
return {
|
||||
range: {
|
||||
[timestampField]: {
|
||||
gte: `now-${getDelayInSecondsFromSLO(slo)}s/m`,
|
||||
},
|
||||
}
|
||||
: {
|
||||
range: {
|
||||
[timestampField]: {
|
||||
gte: `now-${slo.timeWindow.duration.format()}/d`,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (isServerless) {
|
||||
return {
|
||||
range: {
|
||||
[timestampField]: {
|
||||
gte: `now-7d`,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
range: {
|
||||
[timestampField]: {
|
||||
gte: `now-${slo.timeWindow.duration.format()}/d`,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import { HistogramTransformGenerator } from './histogram';
|
|||
import { dataViewsService } from '@kbn/data-views-plugin/server/mocks';
|
||||
|
||||
const SPACE_ID = 'custom-space';
|
||||
const generator = new HistogramTransformGenerator(SPACE_ID, dataViewsService);
|
||||
const generator = new HistogramTransformGenerator(SPACE_ID, dataViewsService, false);
|
||||
|
||||
describe('Histogram Transform Generator', () => {
|
||||
describe('validation', () => {
|
||||
|
|
|
@ -25,8 +25,8 @@ import { GetHistogramIndicatorAggregation } from '../aggregations';
|
|||
import { getFilterRange, getTimesliceTargetComparator } from './common';
|
||||
|
||||
export class HistogramTransformGenerator extends TransformGenerator {
|
||||
constructor(spaceId: string, dataViewService: DataViewsService) {
|
||||
super(spaceId, dataViewService);
|
||||
constructor(spaceId: string, dataViewService: DataViewsService, isServerless: boolean) {
|
||||
super(spaceId, dataViewService, isServerless);
|
||||
}
|
||||
|
||||
public async getTransformParams(slo: SLODefinition): Promise<TransformPutTransformRequest> {
|
||||
|
@ -59,7 +59,7 @@ export class HistogramTransformGenerator extends TransformGenerator {
|
|||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
getFilterRange(slo, indicator.params.timestampField),
|
||||
getFilterRange(slo, indicator.params.timestampField, this.isServerless),
|
||||
getElasticsearchQueryOrThrow(indicator.params.filter, dataView),
|
||||
],
|
||||
},
|
||||
|
|
|
@ -15,7 +15,7 @@ import { KQLCustomTransformGenerator } from './kql_custom';
|
|||
import { dataViewsService } from '@kbn/data-views-plugin/server/mocks';
|
||||
|
||||
const SPACE_ID = 'custom-space';
|
||||
const generator = new KQLCustomTransformGenerator(SPACE_ID, dataViewsService);
|
||||
const generator = new KQLCustomTransformGenerator(SPACE_ID, dataViewsService, false);
|
||||
|
||||
describe('KQL Custom Transform Generator', () => {
|
||||
describe('validation', () => {
|
||||
|
|
|
@ -20,8 +20,8 @@ import { InvalidTransformError } from '../../errors';
|
|||
import { getFilterRange, getTimesliceTargetComparator } from './common';
|
||||
|
||||
export class KQLCustomTransformGenerator extends TransformGenerator {
|
||||
constructor(spaceId: string, dataViewService: DataViewsService) {
|
||||
super(spaceId, dataViewService);
|
||||
constructor(spaceId: string, dataViewService: DataViewsService, isServerless: boolean) {
|
||||
super(spaceId, dataViewService, isServerless);
|
||||
}
|
||||
|
||||
public async getTransformParams(slo: SLODefinition): Promise<TransformPutTransformRequest> {
|
||||
|
@ -53,7 +53,7 @@ export class KQLCustomTransformGenerator extends TransformGenerator {
|
|||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
getFilterRange(slo, indicator.params.timestampField),
|
||||
getFilterRange(slo, indicator.params.timestampField, this.isServerless),
|
||||
getElasticsearchQueryOrThrow(indicator.params.filter),
|
||||
],
|
||||
},
|
||||
|
|
|
@ -15,7 +15,7 @@ import { MetricCustomTransformGenerator } from './metric_custom';
|
|||
import { dataViewsService } from '@kbn/data-views-plugin/server/mocks';
|
||||
|
||||
const SPACE_ID = 'custom-space';
|
||||
const generator = new MetricCustomTransformGenerator(SPACE_ID, dataViewsService);
|
||||
const generator = new MetricCustomTransformGenerator(SPACE_ID, dataViewsService, false);
|
||||
|
||||
describe('Metric Custom Transform Generator', () => {
|
||||
describe('validation', () => {
|
||||
|
|
|
@ -24,8 +24,8 @@ import { getFilterRange, getTimesliceTargetComparator } from './common';
|
|||
export const INVALID_EQUATION_REGEX = /[^A-Z|+|\-|\s|\d+|\.|\(|\)|\/|\*|>|<|=|\?|\:|&|\!|\|]+/g;
|
||||
|
||||
export class MetricCustomTransformGenerator extends TransformGenerator {
|
||||
constructor(spaceId: string, dataViewService: DataViewsService) {
|
||||
super(spaceId, dataViewService);
|
||||
constructor(spaceId: string, dataViewService: DataViewsService, isServerless: boolean) {
|
||||
super(spaceId, dataViewService, isServerless);
|
||||
}
|
||||
|
||||
public async getTransformParams(slo: SLODefinition): Promise<TransformPutTransformRequest> {
|
||||
|
@ -57,7 +57,7 @@ export class MetricCustomTransformGenerator extends TransformGenerator {
|
|||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
getFilterRange(slo, indicator.params.timestampField),
|
||||
getFilterRange(slo, indicator.params.timestampField, this.isServerless),
|
||||
getElasticsearchQueryOrThrow(indicator.params.filter, dataView),
|
||||
],
|
||||
},
|
||||
|
|
|
@ -111,7 +111,7 @@ export class SyntheticsAvailabilityTransformGenerator extends TransformGenerator
|
|||
const queryFilter: estypes.QueryDslQueryContainer[] = [
|
||||
{ term: { 'summary.final_attempt': true } },
|
||||
{ term: { 'meta.space_id': this.spaceId } },
|
||||
getFilterRange(slo, '@timestamp'),
|
||||
getFilterRange(slo, '@timestamp', this.isServerless),
|
||||
];
|
||||
const { monitorIds, tags, projects } = buildParamValues({
|
||||
monitorIds: indicator.params.monitorIds || [],
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
import { TimesliceMetricTransformGenerator } from './timeslice_metric';
|
||||
|
||||
const SPACE_ID = 'custom-space';
|
||||
const generator = new TimesliceMetricTransformGenerator(SPACE_ID, dataViewsService);
|
||||
const generator = new TimesliceMetricTransformGenerator(SPACE_ID, dataViewsService, false);
|
||||
const everythingIndicator = createTimesliceMetricIndicator(
|
||||
[
|
||||
{ name: 'A', aggregation: 'avg', field: 'test.field', filter: 'test.category: "test"' },
|
||||
|
|
|
@ -28,8 +28,8 @@ import { getFilterRange } from './common';
|
|||
const INVALID_EQUATION_REGEX = /[^A-Z|+|\-|\s|\d+|\.|\(|\)|\/|\*|>|<|=|\?|\:|&|\!|\|]+/g;
|
||||
|
||||
export class TimesliceMetricTransformGenerator extends TransformGenerator {
|
||||
constructor(spaceId: string, dataViewService: DataViewsService) {
|
||||
super(spaceId, dataViewService);
|
||||
constructor(spaceId: string, dataViewService: DataViewsService, isServerless: boolean) {
|
||||
super(spaceId, dataViewService, isServerless);
|
||||
}
|
||||
|
||||
public async getTransformParams(slo: SLODefinition): Promise<TransformPutTransformRequest> {
|
||||
|
@ -62,7 +62,7 @@ export class TimesliceMetricTransformGenerator extends TransformGenerator {
|
|||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
getFilterRange(slo, indicator.params.timestampField),
|
||||
getFilterRange(slo, indicator.params.timestampField, this.isServerless),
|
||||
getElasticsearchQueryOrThrow(indicator.params.filter, dataView),
|
||||
],
|
||||
},
|
||||
|
|
|
@ -10,7 +10,11 @@ import { createAPMTransactionErrorRateIndicator, createSLO } from '../fixtures/s
|
|||
import { ApmTransactionErrorRateTransformGenerator } from './apm_transaction_error_rate';
|
||||
import { dataViewsService } from '@kbn/data-views-plugin/server/mocks';
|
||||
|
||||
const generator = new ApmTransactionErrorRateTransformGenerator('my-space-id', dataViewsService);
|
||||
const generator = new ApmTransactionErrorRateTransformGenerator(
|
||||
'my-space-id',
|
||||
dataViewsService,
|
||||
false
|
||||
);
|
||||
|
||||
describe('Transform Generator', () => {
|
||||
describe('buildCommonGroupBy', () => {
|
||||
|
|
|
@ -26,20 +26,34 @@ export function createTransformGenerators(
|
|||
return {
|
||||
'sli.apm.transactionDuration': new ApmTransactionDurationTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService
|
||||
dataViewsService,
|
||||
isServerless
|
||||
),
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService
|
||||
dataViewsService,
|
||||
isServerless
|
||||
),
|
||||
'sli.synthetics.availability': new SyntheticsAvailabilityTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
isServerless
|
||||
),
|
||||
'sli.kql.custom': new KQLCustomTransformGenerator(spaceId, dataViewsService),
|
||||
'sli.metric.custom': new MetricCustomTransformGenerator(spaceId, dataViewsService),
|
||||
'sli.histogram.custom': new HistogramTransformGenerator(spaceId, dataViewsService),
|
||||
'sli.metric.timeslice': new TimesliceMetricTransformGenerator(spaceId, dataViewsService),
|
||||
'sli.kql.custom': new KQLCustomTransformGenerator(spaceId, dataViewsService, isServerless),
|
||||
'sli.metric.custom': new MetricCustomTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
isServerless
|
||||
),
|
||||
'sli.histogram.custom': new HistogramTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
isServerless
|
||||
),
|
||||
'sli.metric.timeslice': new TimesliceMetricTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
isServerless
|
||||
),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -81,7 +81,8 @@ describe('TransformManager', () => {
|
|||
const generators: Record<IndicatorTypes, TransformGenerator> = {
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService
|
||||
dataViewsService,
|
||||
false
|
||||
),
|
||||
};
|
||||
const transformManager = new DefaultTransformManager(
|
||||
|
@ -106,7 +107,8 @@ describe('TransformManager', () => {
|
|||
const generators: Record<IndicatorTypes, TransformGenerator> = {
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService
|
||||
dataViewsService,
|
||||
false
|
||||
),
|
||||
};
|
||||
const transformManager = new DefaultTransformManager(
|
||||
|
@ -129,7 +131,8 @@ describe('TransformManager', () => {
|
|||
const generators: Record<IndicatorTypes, TransformGenerator> = {
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService
|
||||
dataViewsService,
|
||||
false
|
||||
),
|
||||
};
|
||||
const transformManager = new DefaultTransformManager(
|
||||
|
@ -152,7 +155,8 @@ describe('TransformManager', () => {
|
|||
const generators: Record<IndicatorTypes, TransformGenerator> = {
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService
|
||||
dataViewsService,
|
||||
false
|
||||
),
|
||||
};
|
||||
const transformManager = new DefaultTransformManager(
|
||||
|
@ -175,7 +179,8 @@ describe('TransformManager', () => {
|
|||
const generators: Record<IndicatorTypes, TransformGenerator> = {
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService
|
||||
dataViewsService,
|
||||
false
|
||||
),
|
||||
};
|
||||
const transformManager = new DefaultTransformManager(
|
||||
|
@ -199,7 +204,8 @@ describe('TransformManager', () => {
|
|||
const generators: Record<IndicatorTypes, TransformGenerator> = {
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService
|
||||
dataViewsService,
|
||||
false
|
||||
),
|
||||
};
|
||||
const transformManager = new DefaultTransformManager(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue