mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
chore(slo): refactor transform generators and managers dependency injection (#201031)
This commit is contained in:
parent
455a075495
commit
204666310f
23 changed files with 642 additions and 677 deletions
|
@ -29,7 +29,6 @@ import {
|
|||
updateSLOParamsSchema,
|
||||
} from '@kbn/slo-schema';
|
||||
import { getOverviewParamsSchema } from '@kbn/slo-schema/src/rest_specs/routes/get_overview';
|
||||
import type { IndicatorTypes } from '../../domain/models';
|
||||
import { executeWithErrorHandler } from '../../errors';
|
||||
import {
|
||||
CreateSLO,
|
||||
|
@ -60,29 +59,10 @@ import { SloDefinitionClient } from '../../services/slo_definition_client';
|
|||
import { getSloSettings, storeSloSettings } from '../../services/slo_settings';
|
||||
import { DefaultSummarySearchClient } from '../../services/summary_search_client';
|
||||
import { DefaultSummaryTransformGenerator } from '../../services/summary_transform_generator/summary_transform_generator';
|
||||
import {
|
||||
ApmTransactionDurationTransformGenerator,
|
||||
ApmTransactionErrorRateTransformGenerator,
|
||||
HistogramTransformGenerator,
|
||||
KQLCustomTransformGenerator,
|
||||
MetricCustomTransformGenerator,
|
||||
SyntheticsAvailabilityTransformGenerator,
|
||||
TimesliceMetricTransformGenerator,
|
||||
TransformGenerator,
|
||||
} from '../../services/transform_generators';
|
||||
import { createTransformGenerators } from '../../services/transform_generators';
|
||||
import { createSloServerRoute } from '../create_slo_server_route';
|
||||
import { SLORoutesDependencies } from '../types';
|
||||
|
||||
const transformGenerators: Record<IndicatorTypes, TransformGenerator> = {
|
||||
'sli.apm.transactionDuration': new ApmTransactionDurationTransformGenerator(),
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(),
|
||||
'sli.synthetics.availability': new SyntheticsAvailabilityTransformGenerator(),
|
||||
'sli.kql.custom': new KQLCustomTransformGenerator(),
|
||||
'sli.metric.custom': new MetricCustomTransformGenerator(),
|
||||
'sli.histogram.custom': new HistogramTransformGenerator(),
|
||||
'sli.metric.timeslice': new TimesliceMetricTransformGenerator(),
|
||||
};
|
||||
|
||||
const assertPlatinumLicense = async (plugins: SLORoutesDependencies['plugins']) => {
|
||||
const licensing = await plugins.licensing.start();
|
||||
const hasCorrectLicense = (await licensing.getLicense()).hasAtLeast('platinum');
|
||||
|
@ -120,14 +100,18 @@ const createSLORoute = createSloServerRoute({
|
|||
getSpaceId(plugins, request),
|
||||
dataViews.dataViewsServiceFactory(soClient, esClient),
|
||||
]);
|
||||
const transformManager = new DefaultTransformManager(
|
||||
transformGenerators,
|
||||
scopedClusterClient,
|
||||
logger,
|
||||
|
||||
const transformGenerators = createTransformGenerators(
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
sloContext.isServerless
|
||||
);
|
||||
|
||||
const transformManager = new DefaultTransformManager(
|
||||
transformGenerators,
|
||||
scopedClusterClient,
|
||||
logger
|
||||
);
|
||||
const summaryTransformManager = new DefaultSummaryTransformManager(
|
||||
new DefaultSummaryTransformGenerator(),
|
||||
scopedClusterClient,
|
||||
|
@ -168,14 +152,17 @@ const inspectSLORoute = createSloServerRoute({
|
|||
const soClient = core.savedObjects.client;
|
||||
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
|
||||
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
|
||||
const transformManager = new DefaultTransformManager(
|
||||
transformGenerators,
|
||||
scopedClusterClient,
|
||||
logger,
|
||||
|
||||
const transformGenerators = createTransformGenerators(
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
sloContext.isServerless
|
||||
);
|
||||
const transformManager = new DefaultTransformManager(
|
||||
transformGenerators,
|
||||
scopedClusterClient,
|
||||
logger
|
||||
);
|
||||
const summaryTransformManager = new DefaultSummaryTransformManager(
|
||||
new DefaultSummaryTransformGenerator(),
|
||||
scopedClusterClient,
|
||||
|
@ -218,14 +205,17 @@ const updateSLORoute = createSloServerRoute({
|
|||
const soClient = core.savedObjects.client;
|
||||
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
|
||||
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
|
||||
const transformManager = new DefaultTransformManager(
|
||||
transformGenerators,
|
||||
scopedClusterClient,
|
||||
logger,
|
||||
|
||||
const transformGenerators = createTransformGenerators(
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
sloContext.isServerless
|
||||
);
|
||||
const transformManager = new DefaultTransformManager(
|
||||
transformGenerators,
|
||||
scopedClusterClient,
|
||||
logger
|
||||
);
|
||||
const summaryTransformManager = new DefaultSummaryTransformManager(
|
||||
new DefaultSummaryTransformGenerator(),
|
||||
scopedClusterClient,
|
||||
|
@ -271,14 +261,16 @@ const deleteSLORoute = createSloServerRoute({
|
|||
|
||||
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
|
||||
|
||||
const transformGenerators = createTransformGenerators(
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
sloContext.isServerless
|
||||
);
|
||||
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
|
||||
const transformManager = new DefaultTransformManager(
|
||||
transformGenerators,
|
||||
scopedClusterClient,
|
||||
logger,
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
sloContext.isServerless
|
||||
logger
|
||||
);
|
||||
|
||||
const summaryTransformManager = new DefaultSummaryTransformManager(
|
||||
|
@ -346,14 +338,18 @@ const enableSLORoute = createSloServerRoute({
|
|||
const esClient = core.elasticsearch.client.asCurrentUser;
|
||||
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
|
||||
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
|
||||
const transformManager = new DefaultTransformManager(
|
||||
transformGenerators,
|
||||
scopedClusterClient,
|
||||
logger,
|
||||
|
||||
const transformGenerators = createTransformGenerators(
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
sloContext.isServerless
|
||||
);
|
||||
|
||||
const transformManager = new DefaultTransformManager(
|
||||
transformGenerators,
|
||||
scopedClusterClient,
|
||||
logger
|
||||
);
|
||||
const summaryTransformManager = new DefaultSummaryTransformManager(
|
||||
new DefaultSummaryTransformGenerator(),
|
||||
scopedClusterClient,
|
||||
|
@ -388,14 +384,17 @@ const disableSLORoute = createSloServerRoute({
|
|||
const esClient = core.elasticsearch.client.asCurrentUser;
|
||||
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
|
||||
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
|
||||
const transformManager = new DefaultTransformManager(
|
||||
transformGenerators,
|
||||
scopedClusterClient,
|
||||
logger,
|
||||
|
||||
const transformGenerators = createTransformGenerators(
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
sloContext.isServerless
|
||||
);
|
||||
const transformManager = new DefaultTransformManager(
|
||||
transformGenerators,
|
||||
scopedClusterClient,
|
||||
logger
|
||||
);
|
||||
const summaryTransformManager = new DefaultSummaryTransformManager(
|
||||
new DefaultSummaryTransformGenerator(),
|
||||
scopedClusterClient,
|
||||
|
@ -430,14 +429,17 @@ const resetSLORoute = createSloServerRoute({
|
|||
|
||||
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
|
||||
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
|
||||
const transformManager = new DefaultTransformManager(
|
||||
transformGenerators,
|
||||
scopedClusterClient,
|
||||
logger,
|
||||
|
||||
const transformGenerators = createTransformGenerators(
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
sloContext.isServerless
|
||||
);
|
||||
const transformManager = new DefaultTransformManager(
|
||||
transformGenerators,
|
||||
scopedClusterClient,
|
||||
logger
|
||||
);
|
||||
const summaryTransformManager = new DefaultSummaryTransformManager(
|
||||
new DefaultSummaryTransformGenerator(),
|
||||
scopedClusterClient,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Synthetics Availability Transform Generator returns the expected transform params 1`] = `
|
||||
exports[`Synthetics Availability Transform Generator when serverless is disabled returns the expected transform params 1`] = `
|
||||
Object {
|
||||
"_meta": Object {
|
||||
"managed": true,
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Transform Generator builds common runtime mappings and group by with single group by 1`] = `Object {}`;
|
||||
|
||||
exports[`Transform Generator builds common runtime mappings and group by with single group by 2`] = `
|
||||
exports[`Transform Generator buildCommonGroupBy builds common groupBy with single group by 1`] = `
|
||||
Object {
|
||||
"@timestamp": Object {
|
||||
"date_histogram": Object {
|
||||
|
@ -18,9 +16,7 @@ Object {
|
|||
}
|
||||
`;
|
||||
|
||||
exports[`Transform Generator builds common runtime mappings and group by with single group by 3`] = `Object {}`;
|
||||
|
||||
exports[`Transform Generator builds common runtime mappings and group by with single group by 4`] = `
|
||||
exports[`Transform Generator buildCommonGroupBy builds common groupBy with single group by 2`] = `
|
||||
Object {
|
||||
"@timestamp": Object {
|
||||
"date_histogram": Object {
|
||||
|
@ -36,9 +32,7 @@ Object {
|
|||
}
|
||||
`;
|
||||
|
||||
exports[`Transform Generator builds common runtime mappings without multi group by 1`] = `Object {}`;
|
||||
|
||||
exports[`Transform Generator builds common runtime mappings without multi group by 2`] = `
|
||||
exports[`Transform Generator buildCommonGroupBy builds common groupBy with single group by 3`] = `
|
||||
Object {
|
||||
"@timestamp": Object {
|
||||
"date_histogram": Object {
|
||||
|
@ -59,9 +53,7 @@ Object {
|
|||
}
|
||||
`;
|
||||
|
||||
exports[`Transform Generator builds empty runtime mappings without group by 1`] = `Object {}`;
|
||||
|
||||
exports[`Transform Generator builds empty runtime mappings without group by 2`] = `
|
||||
exports[`Transform Generator buildCommonGroupBy builds empty runtime mappings without group by 1`] = `
|
||||
Object {
|
||||
"@timestamp": Object {
|
||||
"date_histogram": Object {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { dataViewsService } from '@kbn/data-views-plugin/server/mocks';
|
||||
import { ALL_VALUE } from '@kbn/slo-schema';
|
||||
import { twoMinute } from '../fixtures/duration';
|
||||
import {
|
||||
|
@ -13,15 +14,14 @@ import {
|
|||
createSLOWithTimeslicesBudgetingMethod,
|
||||
} from '../fixtures/slo';
|
||||
import { ApmTransactionDurationTransformGenerator } from './apm_transaction_duration';
|
||||
import { dataViewsService } from '@kbn/data-views-plugin/server/mocks';
|
||||
|
||||
const generator = new ApmTransactionDurationTransformGenerator();
|
||||
const spaceId = 'custom-space';
|
||||
const SPACE_ID = 'custom-space';
|
||||
const generator = new ApmTransactionDurationTransformGenerator(SPACE_ID, dataViewsService);
|
||||
|
||||
describe('APM Transaction Duration Transform Generator', () => {
|
||||
it('returns the expected transform params with every specified indicator params', async () => {
|
||||
const slo = createSLO({ id: 'irrelevant', indicator: createAPMTransactionDurationIndicator() });
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
});
|
||||
|
@ -31,7 +31,7 @@ describe('APM Transaction Duration Transform Generator', () => {
|
|||
id: 'irrelevant',
|
||||
indicator: createAPMTransactionDurationIndicator(),
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
});
|
||||
|
@ -46,7 +46,7 @@ describe('APM Transaction Duration Transform Generator', () => {
|
|||
timesliceWindow: twoMinute(),
|
||||
},
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
});
|
||||
|
@ -60,7 +60,7 @@ describe('APM Transaction Duration Transform Generator', () => {
|
|||
transactionType: ALL_VALUE,
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query).toMatchSnapshot();
|
||||
});
|
||||
|
@ -72,7 +72,7 @@ describe('APM Transaction Duration Transform Generator', () => {
|
|||
index,
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.index).toEqual(index);
|
||||
});
|
||||
|
@ -84,7 +84,7 @@ describe('APM Transaction Duration Transform Generator', () => {
|
|||
filter,
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query).toMatchSnapshot();
|
||||
});
|
||||
|
@ -99,7 +99,7 @@ describe('APM Transaction Duration Transform Generator', () => {
|
|||
}),
|
||||
});
|
||||
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query).toMatchSnapshot();
|
||||
expect(transform.pivot?.group_by).toMatchSnapshot();
|
||||
|
@ -115,7 +115,7 @@ describe('APM Transaction Duration Transform Generator', () => {
|
|||
}),
|
||||
});
|
||||
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query).toMatchSnapshot();
|
||||
expect(transform.pivot?.group_by).toMatchSnapshot();
|
||||
|
@ -131,7 +131,7 @@ describe('APM Transaction Duration Transform Generator', () => {
|
|||
}),
|
||||
});
|
||||
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query).toMatchSnapshot();
|
||||
expect(transform.pivot?.group_by).toMatchSnapshot();
|
||||
|
@ -147,7 +147,7 @@ describe('APM Transaction Duration Transform Generator', () => {
|
|||
}),
|
||||
});
|
||||
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query).toMatchSnapshot();
|
||||
expect(transform.pivot?.group_by).toMatchSnapshot();
|
||||
|
@ -163,7 +163,7 @@ describe('APM Transaction Duration Transform Generator', () => {
|
|||
},
|
||||
});
|
||||
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
// @ts-ignore
|
||||
const rangeFilter = transform.source.query.bool.filter.find((f) => 'range' in f);
|
||||
|
|
|
@ -8,30 +8,29 @@
|
|||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { AggregationsAggregationContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { DataViewsService } from '@kbn/data-views-plugin/common';
|
||||
import {
|
||||
ALL_VALUE,
|
||||
apmTransactionDurationIndicatorSchema,
|
||||
timeslicesBudgetingMethodSchema,
|
||||
} from '@kbn/slo-schema';
|
||||
import { DataViewsService } from '@kbn/data-views-plugin/common';
|
||||
import { getElasticsearchQueryOrThrow, TransformGenerator } from '.';
|
||||
import { TransformGenerator, getElasticsearchQueryOrThrow } from '.';
|
||||
import {
|
||||
SLO_DESTINATION_INDEX_NAME,
|
||||
getSLOPipelineId,
|
||||
getSLOTransformId,
|
||||
SLO_DESTINATION_INDEX_NAME,
|
||||
} from '../../../common/constants';
|
||||
import { getSLOTransformTemplate } from '../../assets/transform_templates/slo_transform_template';
|
||||
import { APMTransactionDurationIndicator, SLODefinition } from '../../domain/models';
|
||||
import { InvalidTransformError } from '../../errors';
|
||||
import { parseIndex } from './common';
|
||||
import { getTimesliceTargetComparator, getFilterRange } from './common';
|
||||
import { getFilterRange, getTimesliceTargetComparator, parseIndex } from './common';
|
||||
|
||||
export class ApmTransactionDurationTransformGenerator extends TransformGenerator {
|
||||
public async getTransformParams(
|
||||
slo: SLODefinition,
|
||||
spaceId: string,
|
||||
dataViewService: DataViewsService
|
||||
): Promise<TransformPutTransformRequest> {
|
||||
constructor(spaceId: string, dataViewService: DataViewsService) {
|
||||
super(spaceId, dataViewService);
|
||||
}
|
||||
|
||||
public async getTransformParams(slo: SLODefinition): Promise<TransformPutTransformRequest> {
|
||||
if (!apmTransactionDurationIndicatorSchema.is(slo.indicator)) {
|
||||
throw new InvalidTransformError(`Cannot handle SLO of indicator type: ${slo.indicator.type}`);
|
||||
}
|
||||
|
@ -39,7 +38,7 @@ export class ApmTransactionDurationTransformGenerator extends TransformGenerator
|
|||
return getSLOTransformTemplate(
|
||||
this.buildTransformId(slo),
|
||||
this.buildDescription(slo),
|
||||
await this.buildSource(slo, slo.indicator, dataViewService),
|
||||
await this.buildSource(slo, slo.indicator),
|
||||
this.buildDestination(slo),
|
||||
this.buildGroupBy(slo, slo.indicator),
|
||||
this.buildAggregations(slo, slo.indicator),
|
||||
|
@ -75,11 +74,7 @@ export class ApmTransactionDurationTransformGenerator extends TransformGenerator
|
|||
return this.buildCommonGroupBy(slo, '@timestamp', extraGroupByFields);
|
||||
}
|
||||
|
||||
private async buildSource(
|
||||
slo: SLODefinition,
|
||||
indicator: APMTransactionDurationIndicator,
|
||||
dataViewService: DataViewsService
|
||||
) {
|
||||
private async buildSource(slo: SLODefinition, indicator: APMTransactionDurationIndicator) {
|
||||
const queryFilter: estypes.QueryDslQueryContainer[] = [getFilterRange(slo, '@timestamp')];
|
||||
|
||||
if (indicator.params.service !== ALL_VALUE) {
|
||||
|
@ -113,10 +108,7 @@ export class ApmTransactionDurationTransformGenerator extends TransformGenerator
|
|||
},
|
||||
});
|
||||
}
|
||||
const dataView = await this.getIndicatorDataView({
|
||||
dataViewService,
|
||||
dataViewId: indicator.params.dataViewId,
|
||||
});
|
||||
const dataView = await this.getIndicatorDataView(indicator.params.dataViewId);
|
||||
|
||||
if (!!indicator.params.filter) {
|
||||
queryFilter.push(getElasticsearchQueryOrThrow(indicator.params.filter, dataView));
|
||||
|
@ -124,7 +116,7 @@ export class ApmTransactionDurationTransformGenerator extends TransformGenerator
|
|||
|
||||
return {
|
||||
index: parseIndex(indicator.params.index),
|
||||
runtime_mappings: this.buildCommonRuntimeMappings(slo, dataView),
|
||||
runtime_mappings: this.buildCommonRuntimeMappings(dataView),
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { dataViewsService } from '@kbn/data-views-plugin/server/mocks';
|
||||
import { ALL_VALUE } from '@kbn/slo-schema';
|
||||
import { oneMinute, twoMinute } from '../fixtures/duration';
|
||||
import {
|
||||
|
@ -13,10 +14,9 @@ import {
|
|||
createSLOWithTimeslicesBudgetingMethod,
|
||||
} from '../fixtures/slo';
|
||||
import { ApmTransactionErrorRateTransformGenerator } from './apm_transaction_error_rate';
|
||||
import { dataViewsService } from '@kbn/data-views-plugin/server/mocks';
|
||||
|
||||
const generator = new ApmTransactionErrorRateTransformGenerator();
|
||||
const spaceId = 'custom-space';
|
||||
const SPACE_ID = 'custom-space';
|
||||
const generator = new ApmTransactionErrorRateTransformGenerator(SPACE_ID, dataViewsService);
|
||||
|
||||
describe('APM Transaction Error Rate Transform Generator', () => {
|
||||
it('returns the expected transform params with every specified indicator params', async () => {
|
||||
|
@ -24,7 +24,7 @@ describe('APM Transaction Error Rate Transform Generator', () => {
|
|||
id: 'irrelevant',
|
||||
indicator: createAPMTransactionErrorRateIndicator(),
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
});
|
||||
|
@ -34,7 +34,7 @@ describe('APM Transaction Error Rate Transform Generator', () => {
|
|||
id: 'irrelevant',
|
||||
indicator: createAPMTransactionErrorRateIndicator(),
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
});
|
||||
|
@ -49,7 +49,7 @@ describe('APM Transaction Error Rate Transform Generator', () => {
|
|||
timesliceWindow: twoMinute(),
|
||||
},
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
});
|
||||
|
@ -63,7 +63,7 @@ describe('APM Transaction Error Rate Transform Generator', () => {
|
|||
transactionType: ALL_VALUE,
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query).toMatchSnapshot();
|
||||
});
|
||||
|
@ -75,7 +75,7 @@ describe('APM Transaction Error Rate Transform Generator', () => {
|
|||
index,
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.index).toEqual(index);
|
||||
});
|
||||
|
@ -87,7 +87,7 @@ describe('APM Transaction Error Rate Transform Generator', () => {
|
|||
filter,
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query).toMatchSnapshot();
|
||||
});
|
||||
|
@ -102,7 +102,7 @@ describe('APM Transaction Error Rate Transform Generator', () => {
|
|||
}),
|
||||
});
|
||||
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query).toMatchSnapshot();
|
||||
expect(transform.pivot?.group_by).toMatchSnapshot();
|
||||
|
@ -118,7 +118,7 @@ describe('APM Transaction Error Rate Transform Generator', () => {
|
|||
}),
|
||||
});
|
||||
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query).toMatchSnapshot();
|
||||
expect(transform.pivot?.group_by).toMatchSnapshot();
|
||||
|
@ -134,7 +134,7 @@ describe('APM Transaction Error Rate Transform Generator', () => {
|
|||
}),
|
||||
});
|
||||
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query).toMatchSnapshot();
|
||||
expect(transform.pivot?.group_by).toMatchSnapshot();
|
||||
|
@ -150,7 +150,7 @@ describe('APM Transaction Error Rate Transform Generator', () => {
|
|||
}),
|
||||
});
|
||||
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query).toMatchSnapshot();
|
||||
expect(transform.pivot?.group_by).toMatchSnapshot();
|
||||
|
@ -166,7 +166,7 @@ describe('APM Transaction Error Rate Transform Generator', () => {
|
|||
},
|
||||
});
|
||||
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
// @ts-ignore
|
||||
const rangeFilter = transform.source.query.bool.filter.find((f) => 'range' in f);
|
||||
|
|
|
@ -13,11 +13,11 @@ import {
|
|||
apmTransactionErrorRateIndicatorSchema,
|
||||
timeslicesBudgetingMethodSchema,
|
||||
} from '@kbn/slo-schema';
|
||||
import { getElasticsearchQueryOrThrow, TransformGenerator } from '.';
|
||||
import { TransformGenerator, getElasticsearchQueryOrThrow } from '.';
|
||||
import {
|
||||
SLO_DESTINATION_INDEX_NAME,
|
||||
getSLOPipelineId,
|
||||
getSLOTransformId,
|
||||
SLO_DESTINATION_INDEX_NAME,
|
||||
} from '../../../common/constants';
|
||||
import { getSLOTransformTemplate } from '../../assets/transform_templates/slo_transform_template';
|
||||
import { APMTransactionErrorRateIndicator, SLODefinition } from '../../domain/models';
|
||||
|
@ -25,11 +25,11 @@ import { InvalidTransformError } from '../../errors';
|
|||
import { getFilterRange, getTimesliceTargetComparator, parseIndex } from './common';
|
||||
|
||||
export class ApmTransactionErrorRateTransformGenerator extends TransformGenerator {
|
||||
public async getTransformParams(
|
||||
slo: SLODefinition,
|
||||
spaceId: string,
|
||||
dataViewService: DataViewsService
|
||||
): Promise<TransformPutTransformRequest> {
|
||||
constructor(spaceId: string, dataViewService: DataViewsService) {
|
||||
super(spaceId, dataViewService);
|
||||
}
|
||||
|
||||
public async getTransformParams(slo: SLODefinition): Promise<TransformPutTransformRequest> {
|
||||
if (!apmTransactionErrorRateIndicatorSchema.is(slo.indicator)) {
|
||||
throw new InvalidTransformError(`Cannot handle SLO of indicator type: ${slo.indicator.type}`);
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ export class ApmTransactionErrorRateTransformGenerator extends TransformGenerato
|
|||
return getSLOTransformTemplate(
|
||||
this.buildTransformId(slo),
|
||||
this.buildDescription(slo),
|
||||
await this.buildSource(slo, slo.indicator, dataViewService),
|
||||
await this.buildSource(slo, slo.indicator),
|
||||
this.buildDestination(slo),
|
||||
this.buildGroupBy(slo, slo.indicator),
|
||||
this.buildAggregations(slo),
|
||||
|
@ -73,11 +73,7 @@ export class ApmTransactionErrorRateTransformGenerator extends TransformGenerato
|
|||
return this.buildCommonGroupBy(slo, '@timestamp', extraGroupByFields);
|
||||
}
|
||||
|
||||
private async buildSource(
|
||||
slo: SLODefinition,
|
||||
indicator: APMTransactionErrorRateIndicator,
|
||||
dataViewService: DataViewsService
|
||||
) {
|
||||
private async buildSource(slo: SLODefinition, indicator: APMTransactionErrorRateIndicator) {
|
||||
const queryFilter: estypes.QueryDslQueryContainer[] = [getFilterRange(slo, '@timestamp')];
|
||||
|
||||
if (indicator.params.service !== ALL_VALUE) {
|
||||
|
@ -112,10 +108,7 @@ export class ApmTransactionErrorRateTransformGenerator extends TransformGenerato
|
|||
});
|
||||
}
|
||||
|
||||
const dataView = await this.getIndicatorDataView({
|
||||
dataViewService,
|
||||
dataViewId: indicator.params.dataViewId,
|
||||
});
|
||||
const dataView = await this.getIndicatorDataView(indicator.params.dataViewId);
|
||||
|
||||
if (indicator.params.filter) {
|
||||
queryFilter.push(getElasticsearchQueryOrThrow(indicator.params.filter, dataView));
|
||||
|
@ -123,7 +116,7 @@ export class ApmTransactionErrorRateTransformGenerator extends TransformGenerato
|
|||
|
||||
return {
|
||||
index: parseIndex(indicator.params.index),
|
||||
runtime_mappings: this.buildCommonRuntimeMappings(slo, dataView),
|
||||
runtime_mappings: this.buildCommonRuntimeMappings(dataView),
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
|
|
|
@ -14,8 +14,8 @@ import {
|
|||
import { HistogramTransformGenerator } from './histogram';
|
||||
import { dataViewsService } from '@kbn/data-views-plugin/server/mocks';
|
||||
|
||||
const generator = new HistogramTransformGenerator();
|
||||
const spaceId = 'custom-space';
|
||||
const SPACE_ID = 'custom-space';
|
||||
const generator = new HistogramTransformGenerator(SPACE_ID, dataViewsService);
|
||||
|
||||
describe('Histogram Transform Generator', () => {
|
||||
describe('validation', () => {
|
||||
|
@ -32,9 +32,7 @@ describe('Histogram Transform Generator', () => {
|
|||
}),
|
||||
});
|
||||
|
||||
await expect(generator.getTransformParams(anSLO, spaceId, dataViewsService)).rejects.toThrow(
|
||||
/Invalid KQL: foo:/
|
||||
);
|
||||
await expect(generator.getTransformParams(anSLO)).rejects.toThrow(/Invalid KQL: foo:/);
|
||||
});
|
||||
|
||||
it('throws when the total filter is invalid', async () => {
|
||||
|
@ -48,24 +46,20 @@ describe('Histogram Transform Generator', () => {
|
|||
}),
|
||||
});
|
||||
|
||||
await expect(generator.getTransformParams(anSLO, spaceId, dataViewsService)).rejects.toThrow(
|
||||
/Invalid KQL: foo:/
|
||||
);
|
||||
await expect(generator.getTransformParams(anSLO)).rejects.toThrow(/Invalid KQL: foo:/);
|
||||
});
|
||||
|
||||
it('throws when the query_filter is invalid', async () => {
|
||||
const anSLO = createSLO({
|
||||
indicator: createHistogramIndicator({ filter: '{ kql.query: invalid' }),
|
||||
});
|
||||
await expect(generator.getTransformParams(anSLO, spaceId, dataViewsService)).rejects.toThrow(
|
||||
/Invalid KQL/
|
||||
);
|
||||
await expect(generator.getTransformParams(anSLO)).rejects.toThrow(/Invalid KQL/);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns the expected transform params with every specified indicator params', async () => {
|
||||
const anSLO = createSLO({ id: 'irrelevant', indicator: createHistogramIndicator() });
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
});
|
||||
|
@ -75,7 +69,7 @@ describe('Histogram Transform Generator', () => {
|
|||
id: 'irrelevant',
|
||||
indicator: createHistogramIndicator(),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
});
|
||||
|
@ -90,7 +84,7 @@ describe('Histogram Transform Generator', () => {
|
|||
timesliceWindow: twoMinute(),
|
||||
},
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
});
|
||||
|
@ -99,7 +93,7 @@ describe('Histogram Transform Generator', () => {
|
|||
const anSLO = createSLO({
|
||||
indicator: createHistogramIndicator({ filter: 'labels.groupId: group-4' }),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.source.query).toMatchSnapshot();
|
||||
});
|
||||
|
@ -108,7 +102,7 @@ describe('Histogram Transform Generator', () => {
|
|||
const anSLO = createSLO({
|
||||
indicator: createHistogramIndicator({ index: 'my-own-index*' }),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.source.index).toBe('my-own-index*');
|
||||
});
|
||||
|
@ -119,7 +113,7 @@ describe('Histogram Transform Generator', () => {
|
|||
timestampField: 'my-date-field',
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.sync?.time?.field).toBe('my-date-field');
|
||||
// @ts-ignore
|
||||
|
@ -130,7 +124,7 @@ describe('Histogram Transform Generator', () => {
|
|||
const anSLO = createSLO({
|
||||
indicator: createHistogramIndicator(),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.pivot!.aggregations!['slo.numerator']).toMatchSnapshot();
|
||||
});
|
||||
|
@ -147,7 +141,7 @@ describe('Histogram Transform Generator', () => {
|
|||
},
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.pivot!.aggregations!['slo.numerator']).toMatchSnapshot();
|
||||
});
|
||||
|
@ -156,7 +150,7 @@ describe('Histogram Transform Generator', () => {
|
|||
const anSLO = createSLO({
|
||||
indicator: createHistogramIndicator(),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.pivot!.aggregations!['slo.denominator']).toMatchSnapshot();
|
||||
});
|
||||
|
@ -171,7 +165,7 @@ describe('Histogram Transform Generator', () => {
|
|||
},
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.pivot!.aggregations!['slo.denominator']).toMatchSnapshot();
|
||||
});
|
||||
|
@ -186,7 +180,7 @@ describe('Histogram Transform Generator', () => {
|
|||
},
|
||||
});
|
||||
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
// @ts-ignore
|
||||
const rangeFilter = transform.source.query.bool.filter.find((f) => 'range' in f);
|
||||
|
|
|
@ -6,18 +6,17 @@
|
|||
*/
|
||||
|
||||
import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { DataViewsService } from '@kbn/data-views-plugin/common';
|
||||
import {
|
||||
HistogramIndicator,
|
||||
histogramIndicatorSchema,
|
||||
timeslicesBudgetingMethodSchema,
|
||||
} from '@kbn/slo-schema';
|
||||
|
||||
import { DataViewsService } from '@kbn/data-views-plugin/common';
|
||||
import { getElasticsearchQueryOrThrow, parseIndex, TransformGenerator } from '.';
|
||||
import { TransformGenerator, getElasticsearchQueryOrThrow, parseIndex } from '.';
|
||||
import {
|
||||
SLO_DESTINATION_INDEX_NAME,
|
||||
getSLOPipelineId,
|
||||
getSLOTransformId,
|
||||
SLO_DESTINATION_INDEX_NAME,
|
||||
} from '../../../common/constants';
|
||||
import { getSLOTransformTemplate } from '../../assets/transform_templates/slo_transform_template';
|
||||
import { SLODefinition } from '../../domain/models';
|
||||
|
@ -26,11 +25,11 @@ import { GetHistogramIndicatorAggregation } from '../aggregations';
|
|||
import { getFilterRange, getTimesliceTargetComparator } from './common';
|
||||
|
||||
export class HistogramTransformGenerator extends TransformGenerator {
|
||||
public async getTransformParams(
|
||||
slo: SLODefinition,
|
||||
spaceId: string,
|
||||
dataViewService: DataViewsService
|
||||
): Promise<TransformPutTransformRequest> {
|
||||
constructor(spaceId: string, dataViewService: DataViewsService) {
|
||||
super(spaceId, dataViewService);
|
||||
}
|
||||
|
||||
public async getTransformParams(slo: SLODefinition): Promise<TransformPutTransformRequest> {
|
||||
if (!histogramIndicatorSchema.is(slo.indicator)) {
|
||||
throw new InvalidTransformError(`Cannot handle SLO of indicator type: ${slo.indicator.type}`);
|
||||
}
|
||||
|
@ -38,7 +37,7 @@ export class HistogramTransformGenerator extends TransformGenerator {
|
|||
return getSLOTransformTemplate(
|
||||
this.buildTransformId(slo),
|
||||
this.buildDescription(slo),
|
||||
await this.buildSource(slo, slo.indicator, dataViewService),
|
||||
await this.buildSource(slo, slo.indicator),
|
||||
this.buildDestination(slo),
|
||||
this.buildCommonGroupBy(slo, slo.indicator.params.timestampField),
|
||||
this.buildAggregations(slo, slo.indicator),
|
||||
|
@ -51,19 +50,12 @@ export class HistogramTransformGenerator extends TransformGenerator {
|
|||
return getSLOTransformId(slo.id, slo.revision);
|
||||
}
|
||||
|
||||
private async buildSource(
|
||||
slo: SLODefinition,
|
||||
indicator: HistogramIndicator,
|
||||
dataViewService: DataViewsService
|
||||
) {
|
||||
const dataView = await this.getIndicatorDataView({
|
||||
dataViewService,
|
||||
dataViewId: indicator.params.index,
|
||||
});
|
||||
private async buildSource(slo: SLODefinition, indicator: HistogramIndicator) {
|
||||
const dataView = await this.getIndicatorDataView(indicator.params.dataViewId);
|
||||
|
||||
return {
|
||||
index: parseIndex(indicator.params.index),
|
||||
runtime_mappings: this.buildCommonRuntimeMappings(slo, dataView),
|
||||
runtime_mappings: this.buildCommonRuntimeMappings(dataView),
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
|
|
|
@ -14,3 +14,4 @@ export * from './metric_custom';
|
|||
export * from './histogram';
|
||||
export * from './timeslice_metric';
|
||||
export * from './common';
|
||||
export * from './transform_generators_factory';
|
||||
|
|
|
@ -14,8 +14,8 @@ import {
|
|||
import { KQLCustomTransformGenerator } from './kql_custom';
|
||||
import { dataViewsService } from '@kbn/data-views-plugin/server/mocks';
|
||||
|
||||
const generator = new KQLCustomTransformGenerator();
|
||||
const spaceId = 'custom-space';
|
||||
const SPACE_ID = 'custom-space';
|
||||
const generator = new KQLCustomTransformGenerator(SPACE_ID, dataViewsService);
|
||||
|
||||
describe('KQL Custom Transform Generator', () => {
|
||||
describe('validation', () => {
|
||||
|
@ -23,31 +23,25 @@ describe('KQL Custom Transform Generator', () => {
|
|||
const anSLO = createSLO({
|
||||
indicator: createKQLCustomIndicator({ good: '{ kql.query: invalid' }),
|
||||
});
|
||||
await expect(generator.getTransformParams(anSLO, spaceId, dataViewsService)).rejects.toThrow(
|
||||
/Invalid KQL/
|
||||
);
|
||||
await expect(generator.getTransformParams(anSLO)).rejects.toThrow(/Invalid KQL/);
|
||||
});
|
||||
it('throws when the KQL denominator is invalid', async () => {
|
||||
const anSLO = createSLO({
|
||||
indicator: createKQLCustomIndicator({ total: '{ kql.query: invalid' }),
|
||||
});
|
||||
await expect(generator.getTransformParams(anSLO, spaceId, dataViewsService)).rejects.toThrow(
|
||||
/Invalid KQL/
|
||||
);
|
||||
await expect(generator.getTransformParams(anSLO)).rejects.toThrow(/Invalid KQL/);
|
||||
});
|
||||
it('throws when the KQL query_filter is invalid', async () => {
|
||||
const anSLO = createSLO({
|
||||
indicator: createKQLCustomIndicator({ filter: '{ kql.query: invalid' }),
|
||||
});
|
||||
await expect(generator.getTransformParams(anSLO, spaceId, dataViewsService)).rejects.toThrow(
|
||||
/Invalid KQL/
|
||||
);
|
||||
await expect(generator.getTransformParams(anSLO)).rejects.toThrow(/Invalid KQL/);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns the expected transform params with every specified indicator params', async () => {
|
||||
const anSLO = createSLO({ id: 'irrelevant', indicator: createKQLCustomIndicator() });
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
});
|
||||
|
@ -57,7 +51,7 @@ describe('KQL Custom Transform Generator', () => {
|
|||
id: 'irrelevant',
|
||||
indicator: createKQLCustomIndicator(),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
});
|
||||
|
@ -72,7 +66,7 @@ describe('KQL Custom Transform Generator', () => {
|
|||
timesliceWindow: twoMinute(),
|
||||
},
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
});
|
||||
|
@ -81,7 +75,7 @@ describe('KQL Custom Transform Generator', () => {
|
|||
const anSLO = createSLO({
|
||||
indicator: createKQLCustomIndicator({ filter: 'labels.groupId: group-4' }),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.source.query).toMatchSnapshot();
|
||||
});
|
||||
|
@ -90,7 +84,7 @@ describe('KQL Custom Transform Generator', () => {
|
|||
const anSLO = createSLO({
|
||||
indicator: createKQLCustomIndicator({ index: 'my-own-index*' }),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.source.index).toBe('my-own-index*');
|
||||
});
|
||||
|
@ -101,7 +95,7 @@ describe('KQL Custom Transform Generator', () => {
|
|||
timestampField: 'my-date-field',
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.sync?.time?.field).toBe('my-date-field');
|
||||
// @ts-ignore
|
||||
|
@ -114,7 +108,7 @@ describe('KQL Custom Transform Generator', () => {
|
|||
good: 'latency < 400 and (http.status_code: 2xx or http.status_code: 3xx or http.status_code: 4xx)',
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.pivot!.aggregations!['slo.numerator']).toMatchSnapshot();
|
||||
});
|
||||
|
@ -125,7 +119,7 @@ describe('KQL Custom Transform Generator', () => {
|
|||
total: 'http.status_code: *',
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.pivot!.aggregations!['slo.denominator']).toMatchSnapshot();
|
||||
});
|
||||
|
@ -140,7 +134,7 @@ describe('KQL Custom Transform Generator', () => {
|
|||
},
|
||||
});
|
||||
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
// @ts-ignore
|
||||
const rangeFilter = transform.source.query.bool.filter.find((f) => 'range' in f);
|
||||
|
|
|
@ -6,14 +6,13 @@
|
|||
*/
|
||||
|
||||
import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { kqlCustomIndicatorSchema, timeslicesBudgetingMethodSchema } from '@kbn/slo-schema';
|
||||
|
||||
import { DataViewsService } from '@kbn/data-views-plugin/common';
|
||||
import { getElasticsearchQueryOrThrow, parseIndex, TransformGenerator } from '.';
|
||||
import { kqlCustomIndicatorSchema, timeslicesBudgetingMethodSchema } from '@kbn/slo-schema';
|
||||
import { TransformGenerator, getElasticsearchQueryOrThrow, parseIndex } from '.';
|
||||
import {
|
||||
SLO_DESTINATION_INDEX_NAME,
|
||||
getSLOPipelineId,
|
||||
getSLOTransformId,
|
||||
SLO_DESTINATION_INDEX_NAME,
|
||||
} from '../../../common/constants';
|
||||
import { getSLOTransformTemplate } from '../../assets/transform_templates/slo_transform_template';
|
||||
import { KQLCustomIndicator, SLODefinition } from '../../domain/models';
|
||||
|
@ -21,11 +20,11 @@ import { InvalidTransformError } from '../../errors';
|
|||
import { getFilterRange, getTimesliceTargetComparator } from './common';
|
||||
|
||||
export class KQLCustomTransformGenerator extends TransformGenerator {
|
||||
public async getTransformParams(
|
||||
slo: SLODefinition,
|
||||
spaceId: string,
|
||||
dataViewService: DataViewsService
|
||||
): Promise<TransformPutTransformRequest> {
|
||||
constructor(spaceId: string, dataViewService: DataViewsService) {
|
||||
super(spaceId, dataViewService);
|
||||
}
|
||||
|
||||
public async getTransformParams(slo: SLODefinition): Promise<TransformPutTransformRequest> {
|
||||
if (!kqlCustomIndicatorSchema.is(slo.indicator)) {
|
||||
throw new InvalidTransformError(`Cannot handle SLO of indicator type: ${slo.indicator.type}`);
|
||||
}
|
||||
|
@ -33,7 +32,7 @@ export class KQLCustomTransformGenerator extends TransformGenerator {
|
|||
return getSLOTransformTemplate(
|
||||
this.buildTransformId(slo),
|
||||
this.buildDescription(slo),
|
||||
await this.buildSource(slo, slo.indicator, dataViewService),
|
||||
await this.buildSource(slo, slo.indicator),
|
||||
this.buildDestination(slo),
|
||||
this.buildCommonGroupBy(slo, slo.indicator.params.timestampField),
|
||||
this.buildAggregations(slo, slo.indicator),
|
||||
|
@ -46,18 +45,11 @@ export class KQLCustomTransformGenerator extends TransformGenerator {
|
|||
return getSLOTransformId(slo.id, slo.revision);
|
||||
}
|
||||
|
||||
private async buildSource(
|
||||
slo: SLODefinition,
|
||||
indicator: KQLCustomIndicator,
|
||||
dataViewService: DataViewsService
|
||||
) {
|
||||
const dataView = await this.getIndicatorDataView({
|
||||
dataViewService,
|
||||
dataViewId: indicator.params.dataViewId,
|
||||
});
|
||||
private async buildSource(slo: SLODefinition, indicator: KQLCustomIndicator) {
|
||||
const dataView = await this.getIndicatorDataView(indicator.params.dataViewId);
|
||||
return {
|
||||
index: parseIndex(indicator.params.index),
|
||||
runtime_mappings: this.buildCommonRuntimeMappings(slo, dataView),
|
||||
runtime_mappings: this.buildCommonRuntimeMappings(dataView),
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
|
|
|
@ -14,8 +14,8 @@ import {
|
|||
import { MetricCustomTransformGenerator } from './metric_custom';
|
||||
import { dataViewsService } from '@kbn/data-views-plugin/server/mocks';
|
||||
|
||||
const generator = new MetricCustomTransformGenerator();
|
||||
const spaceId = 'custom-space';
|
||||
const SPACE_ID = 'custom-space';
|
||||
const generator = new MetricCustomTransformGenerator(SPACE_ID, dataViewsService);
|
||||
|
||||
describe('Metric Custom Transform Generator', () => {
|
||||
describe('validation', () => {
|
||||
|
@ -28,9 +28,7 @@ describe('Metric Custom Transform Generator', () => {
|
|||
},
|
||||
}),
|
||||
});
|
||||
await expect(generator.getTransformParams(anSLO, spaceId, dataViewsService)).rejects.toThrow(
|
||||
/Invalid equation/
|
||||
);
|
||||
await expect(generator.getTransformParams(anSLO)).rejects.toThrow(/Invalid equation/);
|
||||
});
|
||||
it('throws when the good filter is invalid', async () => {
|
||||
const anSLO = createSLO({
|
||||
|
@ -41,9 +39,7 @@ describe('Metric Custom Transform Generator', () => {
|
|||
},
|
||||
}),
|
||||
});
|
||||
await expect(generator.getTransformParams(anSLO, spaceId, dataViewsService)).rejects.toThrow(
|
||||
/Invalid KQL: foo:/
|
||||
);
|
||||
await expect(generator.getTransformParams(anSLO)).rejects.toThrow(/Invalid KQL: foo:/);
|
||||
});
|
||||
it('throws when the total equation is invalid', async () => {
|
||||
const anSLO = createSLO({
|
||||
|
@ -54,9 +50,7 @@ describe('Metric Custom Transform Generator', () => {
|
|||
},
|
||||
}),
|
||||
});
|
||||
await expect(generator.getTransformParams(anSLO, spaceId, dataViewsService)).rejects.toThrow(
|
||||
/Invalid equation/
|
||||
);
|
||||
await expect(generator.getTransformParams(anSLO)).rejects.toThrow(/Invalid equation/);
|
||||
});
|
||||
it('throws when the total filter is invalid', async () => {
|
||||
const anSLO = createSLO({
|
||||
|
@ -67,23 +61,19 @@ describe('Metric Custom Transform Generator', () => {
|
|||
},
|
||||
}),
|
||||
});
|
||||
await expect(() =>
|
||||
generator.getTransformParams(anSLO, spaceId, dataViewsService)
|
||||
).rejects.toThrow(/Invalid KQL: foo:/);
|
||||
await expect(() => generator.getTransformParams(anSLO)).rejects.toThrow(/Invalid KQL: foo:/);
|
||||
});
|
||||
it('throws when the query_filter is invalid', async () => {
|
||||
const anSLO = createSLO({
|
||||
indicator: createMetricCustomIndicator({ filter: '{ kql.query: invalid' }),
|
||||
});
|
||||
await expect(() =>
|
||||
generator.getTransformParams(anSLO, spaceId, dataViewsService)
|
||||
).rejects.toThrow(/Invalid KQL/);
|
||||
await expect(() => generator.getTransformParams(anSLO)).rejects.toThrow(/Invalid KQL/);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns the expected transform params with every specified indicator params', async () => {
|
||||
const anSLO = createSLO({ id: 'irrelevant', indicator: createMetricCustomIndicator() });
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
});
|
||||
|
@ -93,7 +83,7 @@ describe('Metric Custom Transform Generator', () => {
|
|||
id: 'irrelevant',
|
||||
indicator: createMetricCustomIndicator(),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
});
|
||||
|
@ -102,7 +92,7 @@ describe('Metric Custom Transform Generator', () => {
|
|||
const anSLO = createSLO({
|
||||
indicator: createMetricCustomIndicator({ filter: 'labels.groupId: group-4' }),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.source.query).toMatchSnapshot();
|
||||
});
|
||||
|
@ -111,7 +101,7 @@ describe('Metric Custom Transform Generator', () => {
|
|||
const anSLO = createSLO({
|
||||
indicator: createMetricCustomIndicator({ index: 'my-own-index*' }),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.source.index).toBe('my-own-index*');
|
||||
});
|
||||
|
@ -122,7 +112,7 @@ describe('Metric Custom Transform Generator', () => {
|
|||
timestampField: 'my-date-field',
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.sync?.time?.field).toBe('my-date-field');
|
||||
// @ts-ignore
|
||||
|
@ -138,7 +128,7 @@ describe('Metric Custom Transform Generator', () => {
|
|||
},
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.pivot!.aggregations!['slo.numerator']).toMatchSnapshot();
|
||||
});
|
||||
|
@ -152,7 +142,7 @@ describe('Metric Custom Transform Generator', () => {
|
|||
},
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.pivot!.aggregations!['slo.numerator']).toMatchSnapshot();
|
||||
});
|
||||
|
@ -168,7 +158,7 @@ describe('Metric Custom Transform Generator', () => {
|
|||
},
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.pivot!.aggregations!['slo.numerator']).toMatchSnapshot();
|
||||
});
|
||||
|
@ -182,7 +172,7 @@ describe('Metric Custom Transform Generator', () => {
|
|||
},
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.pivot!.aggregations!['slo.numerator']).toMatchSnapshot();
|
||||
});
|
||||
|
@ -196,7 +186,7 @@ describe('Metric Custom Transform Generator', () => {
|
|||
},
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.pivot!.aggregations!['slo.denominator']).toMatchSnapshot();
|
||||
});
|
||||
|
@ -210,7 +200,7 @@ describe('Metric Custom Transform Generator', () => {
|
|||
},
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.pivot!.aggregations!['slo.denominator']).toMatchSnapshot();
|
||||
});
|
||||
|
@ -224,7 +214,7 @@ describe('Metric Custom Transform Generator', () => {
|
|||
},
|
||||
}),
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.pivot!.aggregations!['slo.denominator']).toMatchSnapshot();
|
||||
});
|
||||
|
@ -239,7 +229,7 @@ describe('Metric Custom Transform Generator', () => {
|
|||
},
|
||||
});
|
||||
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
// @ts-ignore
|
||||
const rangeFilter = transform.source.query.bool.filter.find((f) => 'range' in f);
|
||||
|
|
|
@ -24,11 +24,11 @@ import { getFilterRange, getTimesliceTargetComparator } from './common';
|
|||
export const INVALID_EQUATION_REGEX = /[^A-Z|+|\-|\s|\d+|\.|\(|\)|\/|\*|>|<|=|\?|\:|&|\!|\|]+/g;
|
||||
|
||||
export class MetricCustomTransformGenerator extends TransformGenerator {
|
||||
public async getTransformParams(
|
||||
slo: SLODefinition,
|
||||
spaceId: string,
|
||||
dataViewService: DataViewsService
|
||||
): Promise<TransformPutTransformRequest> {
|
||||
constructor(spaceId: string, dataViewService: DataViewsService) {
|
||||
super(spaceId, dataViewService);
|
||||
}
|
||||
|
||||
public async getTransformParams(slo: SLODefinition): Promise<TransformPutTransformRequest> {
|
||||
if (!metricCustomIndicatorSchema.is(slo.indicator)) {
|
||||
throw new InvalidTransformError(`Cannot handle SLO of indicator type: ${slo.indicator.type}`);
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ export class MetricCustomTransformGenerator extends TransformGenerator {
|
|||
return getSLOTransformTemplate(
|
||||
this.buildTransformId(slo),
|
||||
this.buildDescription(slo),
|
||||
await this.buildSource(slo, slo.indicator, dataViewService),
|
||||
await this.buildSource(slo, slo.indicator),
|
||||
this.buildDestination(slo),
|
||||
this.buildCommonGroupBy(slo, slo.indicator.params.timestampField),
|
||||
this.buildAggregations(slo, slo.indicator),
|
||||
|
@ -49,18 +49,11 @@ export class MetricCustomTransformGenerator extends TransformGenerator {
|
|||
return getSLOTransformId(slo.id, slo.revision);
|
||||
}
|
||||
|
||||
private async buildSource(
|
||||
slo: SLODefinition,
|
||||
indicator: MetricCustomIndicator,
|
||||
dataViewService: DataViewsService
|
||||
) {
|
||||
const dataView = await this.getIndicatorDataView({
|
||||
dataViewService,
|
||||
dataViewId: indicator.params.dataViewId,
|
||||
});
|
||||
private async buildSource(slo: SLODefinition, indicator: MetricCustomIndicator) {
|
||||
const dataView = await this.getIndicatorDataView(indicator.params.dataViewId);
|
||||
return {
|
||||
index: parseIndex(indicator.params.index),
|
||||
runtime_mappings: this.buildCommonRuntimeMappings(slo, dataView),
|
||||
runtime_mappings: this.buildCommonRuntimeMappings(dataView),
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
|
|
|
@ -12,286 +12,330 @@ import { twoMinute } from '../fixtures/duration';
|
|||
import { createSLO, createSyntheticsAvailabilityIndicator } from '../fixtures/slo';
|
||||
import { SyntheticsAvailabilityTransformGenerator } from './synthetics_availability';
|
||||
|
||||
const generator = new SyntheticsAvailabilityTransformGenerator();
|
||||
const SPACE_ID = 'custom-space';
|
||||
|
||||
describe('Synthetics Availability Transform Generator', () => {
|
||||
const spaceId = 'custom-space';
|
||||
|
||||
it('returns the expected transform params', async () => {
|
||||
const slo = createSLO({ id: 'irrelevant', indicator: createSyntheticsAvailabilityIndicator() });
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService, false);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
expect(transform.source.query?.bool?.filter).toContainEqual({
|
||||
term: {
|
||||
'summary.final_attempt': true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('groups by config id and observer.name when using default groupings', async () => {
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: createSyntheticsAvailabilityIndicator(),
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService, false);
|
||||
|
||||
expect(transform.pivot?.group_by).toEqual(
|
||||
expect.objectContaining({
|
||||
'monitor.config_id': {
|
||||
terms: {
|
||||
field: 'config_id',
|
||||
},
|
||||
},
|
||||
'observer.name': {
|
||||
terms: {
|
||||
field: 'observer.name',
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('does not include config id and observer.name when using non default groupings', async () => {
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: createSyntheticsAvailabilityIndicator(),
|
||||
groupBy: ['host.name'],
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService, false);
|
||||
|
||||
expect(transform.pivot?.group_by).not.toEqual(
|
||||
expect.objectContaining({
|
||||
'monitor.config_id': {
|
||||
terms: {
|
||||
field: 'config_id',
|
||||
},
|
||||
},
|
||||
'observer.name': {
|
||||
terms: {
|
||||
field: 'observer.name',
|
||||
},
|
||||
},
|
||||
})
|
||||
describe('when serverless is disabled', () => {
|
||||
const generator = new SyntheticsAvailabilityTransformGenerator(
|
||||
SPACE_ID,
|
||||
dataViewsService,
|
||||
false
|
||||
);
|
||||
|
||||
expect(transform.pivot?.group_by).toEqual(
|
||||
expect.objectContaining({
|
||||
'slo.groupings.host.name': {
|
||||
terms: {
|
||||
field: 'host.name',
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it.each([[[]], [[ALL_VALUE]]])(
|
||||
'adds observer.geo.name and monitor.name to groupings key by default, multi group by',
|
||||
async (groupBy) => {
|
||||
it('returns the expected transform params', async () => {
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: createSyntheticsAvailabilityIndicator(),
|
||||
groupBy,
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService, false);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
expect(transform.source.query?.bool?.filter).toContainEqual({
|
||||
term: {
|
||||
'summary.final_attempt': true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('groups by config id and observer.name when using default groupings', async () => {
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: createSyntheticsAvailabilityIndicator(),
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.pivot?.group_by).toEqual(
|
||||
expect.objectContaining({
|
||||
'slo.groupings.monitor.name': {
|
||||
'monitor.config_id': {
|
||||
terms: {
|
||||
field: 'monitor.name',
|
||||
field: 'config_id',
|
||||
},
|
||||
},
|
||||
'slo.groupings.observer.geo.name': {
|
||||
'observer.name': {
|
||||
terms: {
|
||||
field: 'observer.geo.name',
|
||||
field: 'observer.name',
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it.each([[''], [ALL_VALUE]])(
|
||||
'adds observer.geo.name and monitor.name to groupings key by default, single group by',
|
||||
async (groupBy) => {
|
||||
it('does not include config id and observer.name when using non default groupings', async () => {
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: createSyntheticsAvailabilityIndicator(),
|
||||
groupBy,
|
||||
groupBy: ['host.name'],
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService, false);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.pivot?.group_by).toEqual(
|
||||
expect(transform.pivot?.group_by).not.toEqual(
|
||||
expect.objectContaining({
|
||||
'slo.groupings.monitor.name': {
|
||||
'monitor.config_id': {
|
||||
terms: {
|
||||
field: 'monitor.name',
|
||||
field: 'config_id',
|
||||
},
|
||||
},
|
||||
'slo.groupings.observer.geo.name': {
|
||||
'observer.name': {
|
||||
terms: {
|
||||
field: 'observer.geo.name',
|
||||
field: 'observer.name',
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
it.each([['host.name'], [['host.name']]])('handles custom groupBy', async (groupBy) => {
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: createSyntheticsAvailabilityIndicator(),
|
||||
groupBy,
|
||||
expect(transform.pivot?.group_by).toEqual(
|
||||
expect.objectContaining({
|
||||
'slo.groupings.host.name': {
|
||||
terms: {
|
||||
field: 'host.name',
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService, false);
|
||||
|
||||
expect(transform.pivot?.group_by).toEqual(
|
||||
expect.objectContaining({
|
||||
'slo.groupings.host.name': {
|
||||
terms: {
|
||||
field: 'host.name',
|
||||
it.each([[[]], [[ALL_VALUE]]])(
|
||||
'adds observer.geo.name and monitor.name to groupings key by default, multi group by',
|
||||
async (groupBy) => {
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: createSyntheticsAvailabilityIndicator(),
|
||||
groupBy,
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.pivot?.group_by).toEqual(
|
||||
expect.objectContaining({
|
||||
'slo.groupings.monitor.name': {
|
||||
terms: {
|
||||
field: 'monitor.name',
|
||||
},
|
||||
},
|
||||
'slo.groupings.observer.geo.name': {
|
||||
terms: {
|
||||
field: 'observer.geo.name',
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
it.each([[''], [ALL_VALUE]])(
|
||||
'adds observer.geo.name and monitor.name to groupings key by default, single group by',
|
||||
async (groupBy) => {
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: createSyntheticsAvailabilityIndicator(),
|
||||
groupBy,
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.pivot?.group_by).toEqual(
|
||||
expect.objectContaining({
|
||||
'slo.groupings.monitor.name': {
|
||||
terms: {
|
||||
field: 'monitor.name',
|
||||
},
|
||||
},
|
||||
'slo.groupings.observer.geo.name': {
|
||||
terms: {
|
||||
field: 'observer.geo.name',
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
it.each([[['host.name']], [['host.name', 'host.region']]])(
|
||||
'handles custom groupBy',
|
||||
async (groupBy) => {
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: createSyntheticsAvailabilityIndicator(),
|
||||
groupBy,
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.pivot?.group_by).toEqual(
|
||||
expect.objectContaining({
|
||||
'slo.groupings.host.name': {
|
||||
terms: {
|
||||
field: 'host.name',
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
it('filters by summary.final_attempt', async () => {
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: createSyntheticsAvailabilityIndicator(),
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query?.bool?.filter).toContainEqual({
|
||||
term: {
|
||||
'summary.final_attempt': true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('adds tag filters', async () => {
|
||||
const tags = [
|
||||
{ value: 'tag-1', label: 'tag1' },
|
||||
{ value: 'tag-2', label: 'tag2' },
|
||||
];
|
||||
const indicator = createSyntheticsAvailabilityIndicator();
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: {
|
||||
...indicator,
|
||||
params: {
|
||||
...indicator.params,
|
||||
tags,
|
||||
},
|
||||
} as SLODefinition['indicator'],
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query?.bool?.filter).toContainEqual({
|
||||
terms: {
|
||||
tags: ['tag-1', 'tag-2'],
|
||||
},
|
||||
});
|
||||
expect(transform.pivot?.group_by?.tags).toEqual({
|
||||
terms: {
|
||||
field: 'tags',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('adds monitorId filter', async () => {
|
||||
const monitorIds = [
|
||||
{ value: 'id-1', label: 'Monitor name 1' },
|
||||
{ value: 'id-2', label: 'Monitor name 2' },
|
||||
];
|
||||
const indicator = createSyntheticsAvailabilityIndicator();
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: {
|
||||
...indicator,
|
||||
params: {
|
||||
...indicator.params,
|
||||
monitorIds,
|
||||
},
|
||||
} as SLODefinition['indicator'],
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query?.bool?.filter).toContainEqual({
|
||||
terms: {
|
||||
'monitor.id': ['id-1', 'id-2'],
|
||||
},
|
||||
});
|
||||
expect(transform.pivot?.group_by?.['monitor.id']).toEqual({
|
||||
terms: {
|
||||
field: 'monitor.id',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('adds project id filter', async () => {
|
||||
const projects = [
|
||||
{ value: 'id-1', label: 'Project name 1' },
|
||||
{ value: 'id-2', label: 'Project name 2' },
|
||||
];
|
||||
const indicator = createSyntheticsAvailabilityIndicator();
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: {
|
||||
...indicator,
|
||||
params: {
|
||||
...indicator.params,
|
||||
projects,
|
||||
},
|
||||
} as SLODefinition['indicator'],
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query?.bool?.filter).toContainEqual({
|
||||
terms: {
|
||||
'monitor.project.id': ['id-1', 'id-2'],
|
||||
},
|
||||
});
|
||||
expect(transform.pivot?.group_by?.['monitor.project.id']).toEqual({
|
||||
terms: {
|
||||
field: 'monitor.project.id',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('filters by space', async () => {
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: createSyntheticsAvailabilityIndicator(),
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query?.bool?.filter).toContainEqual({
|
||||
term: {
|
||||
'meta.space_id': SPACE_ID,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("overrides the range filter when 'preventInitialBackfill' is true", async () => {
|
||||
const slo = createSLO({
|
||||
indicator: createSyntheticsAvailabilityIndicator(),
|
||||
settings: {
|
||||
frequency: twoMinute(),
|
||||
syncDelay: twoMinute(),
|
||||
preventInitialBackfill: true,
|
||||
},
|
||||
});
|
||||
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
// @ts-ignore
|
||||
const rangeFilter = transform.source.query.bool.filter.find((f) => 'range' in f);
|
||||
|
||||
expect(rangeFilter).toEqual({
|
||||
range: {
|
||||
'@timestamp': {
|
||||
gte: 'now-300s/m', // 2m + 2m + 60s
|
||||
},
|
||||
},
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
it("uses the 'event.ingested' as syncField", async () => {
|
||||
const slo = createSLO({
|
||||
indicator: createSyntheticsAvailabilityIndicator(),
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.sync?.time?.field).toEqual('event.ingested');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when serverless is enabled', () => {
|
||||
const generator = new SyntheticsAvailabilityTransformGenerator(
|
||||
SPACE_ID,
|
||||
dataViewsService,
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('filters by summary.final_attempt', async () => {
|
||||
const slo = createSLO({ id: 'irrelevant', indicator: createSyntheticsAvailabilityIndicator() });
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService, false);
|
||||
it("overrides the syncField with '@timestamp'", async () => {
|
||||
const slo = createSLO({
|
||||
indicator: createSyntheticsAvailabilityIndicator(),
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
expect(transform.source.query?.bool?.filter).toContainEqual({
|
||||
term: {
|
||||
'summary.final_attempt': true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('adds tag filters', async () => {
|
||||
const tags = [
|
||||
{ value: 'tag-1', label: 'tag1' },
|
||||
{ value: 'tag-2', label: 'tag2' },
|
||||
];
|
||||
const indicator = createSyntheticsAvailabilityIndicator();
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: {
|
||||
...indicator,
|
||||
params: {
|
||||
...indicator.params,
|
||||
tags,
|
||||
},
|
||||
} as SLODefinition['indicator'],
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService, false);
|
||||
|
||||
expect(transform.source.query?.bool?.filter).toContainEqual({
|
||||
terms: {
|
||||
tags: ['tag-1', 'tag-2'],
|
||||
},
|
||||
});
|
||||
expect(transform.pivot?.group_by?.tags).toEqual({
|
||||
terms: {
|
||||
field: 'tags',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('adds monitorId filter', async () => {
|
||||
const monitorIds = [
|
||||
{ value: 'id-1', label: 'Monitor name 1' },
|
||||
{ value: 'id-2', label: 'Monitor name 2' },
|
||||
];
|
||||
const indicator = createSyntheticsAvailabilityIndicator();
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: {
|
||||
...indicator,
|
||||
params: {
|
||||
...indicator.params,
|
||||
monitorIds,
|
||||
},
|
||||
} as SLODefinition['indicator'],
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService, false);
|
||||
|
||||
expect(transform.source.query?.bool?.filter).toContainEqual({
|
||||
terms: {
|
||||
'monitor.id': ['id-1', 'id-2'],
|
||||
},
|
||||
});
|
||||
expect(transform.pivot?.group_by?.['monitor.id']).toEqual({
|
||||
terms: {
|
||||
field: 'monitor.id',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('adds project id filter', async () => {
|
||||
const projects = [
|
||||
{ value: 'id-1', label: 'Project name 1' },
|
||||
{ value: 'id-2', label: 'Project name 2' },
|
||||
];
|
||||
const indicator = createSyntheticsAvailabilityIndicator();
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: {
|
||||
...indicator,
|
||||
params: {
|
||||
...indicator.params,
|
||||
projects,
|
||||
},
|
||||
} as SLODefinition['indicator'],
|
||||
});
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService, false);
|
||||
|
||||
expect(transform.source.query?.bool?.filter).toContainEqual({
|
||||
terms: {
|
||||
'monitor.project.id': ['id-1', 'id-2'],
|
||||
},
|
||||
});
|
||||
expect(transform.pivot?.group_by?.['monitor.project.id']).toEqual({
|
||||
terms: {
|
||||
field: 'monitor.project.id',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('filters by space', async () => {
|
||||
const slo = createSLO({ id: 'irrelevant', indicator: createSyntheticsAvailabilityIndicator() });
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService, false);
|
||||
|
||||
expect(transform.source.query?.bool?.filter).toContainEqual({
|
||||
term: {
|
||||
'meta.space_id': spaceId,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("overrides the range filter when 'preventInitialBackfill' is true", async () => {
|
||||
const slo = createSLO({
|
||||
indicator: createSyntheticsAvailabilityIndicator(),
|
||||
settings: {
|
||||
frequency: twoMinute(),
|
||||
syncDelay: twoMinute(),
|
||||
preventInitialBackfill: true,
|
||||
},
|
||||
});
|
||||
|
||||
const transform = await generator.getTransformParams(slo, 'default', dataViewsService, false);
|
||||
|
||||
// @ts-ignore
|
||||
const rangeFilter = transform.source.query.bool.filter.find((f) => 'range' in f);
|
||||
|
||||
expect(rangeFilter).toEqual({
|
||||
range: {
|
||||
'@timestamp': {
|
||||
gte: 'now-300s/m', // 2m + 2m + 60s
|
||||
},
|
||||
},
|
||||
expect(transform.sync?.time?.field).toEqual('@timestamp');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -28,12 +28,11 @@ import { InvalidTransformError } from '../../errors';
|
|||
import { getFilterRange } from './common';
|
||||
|
||||
export class SyntheticsAvailabilityTransformGenerator extends TransformGenerator {
|
||||
public async getTransformParams(
|
||||
slo: SLODefinition,
|
||||
spaceId: string,
|
||||
dataViewService: DataViewsService,
|
||||
isServerless: boolean
|
||||
): Promise<TransformPutTransformRequest> {
|
||||
constructor(spaceId: string, dataViewService: DataViewsService, isServerless: boolean) {
|
||||
super(spaceId, dataViewService, isServerless);
|
||||
}
|
||||
|
||||
public async getTransformParams(slo: SLODefinition): Promise<TransformPutTransformRequest> {
|
||||
if (!syntheticsAvailabilityIndicatorSchema.is(slo.indicator)) {
|
||||
throw new InvalidTransformError(`Cannot handle SLO of indicator type: ${slo.indicator.type}`);
|
||||
}
|
||||
|
@ -41,11 +40,11 @@ export class SyntheticsAvailabilityTransformGenerator extends TransformGenerator
|
|||
return getSLOTransformTemplate(
|
||||
this.buildTransformId(slo),
|
||||
this.buildDescription(slo),
|
||||
await this.buildSource(slo, slo.indicator, spaceId, dataViewService),
|
||||
await this.buildSource(slo, slo.indicator),
|
||||
this.buildDestination(slo),
|
||||
this.buildGroupBy(slo, slo.indicator),
|
||||
this.buildAggregations(slo),
|
||||
this.buildSettings(slo, isServerless ? '@timestamp' : 'event.ingested'),
|
||||
this.buildSettings(slo, this.isServerless ? '@timestamp' : 'event.ingested'),
|
||||
slo
|
||||
);
|
||||
}
|
||||
|
@ -108,15 +107,10 @@ export class SyntheticsAvailabilityTransformGenerator extends TransformGenerator
|
|||
);
|
||||
}
|
||||
|
||||
private async buildSource(
|
||||
slo: SLODefinition,
|
||||
indicator: SyntheticsAvailabilityIndicator,
|
||||
spaceId: string,
|
||||
dataViewService: DataViewsService
|
||||
) {
|
||||
private async buildSource(slo: SLODefinition, indicator: SyntheticsAvailabilityIndicator) {
|
||||
const queryFilter: estypes.QueryDslQueryContainer[] = [
|
||||
{ term: { 'summary.final_attempt': true } },
|
||||
{ term: { 'meta.space_id': spaceId } },
|
||||
{ term: { 'meta.space_id': this.spaceId } },
|
||||
getFilterRange(slo, '@timestamp'),
|
||||
];
|
||||
const { monitorIds, tags, projects } = buildParamValues({
|
||||
|
@ -153,14 +147,11 @@ export class SyntheticsAvailabilityTransformGenerator extends TransformGenerator
|
|||
queryFilter.push(getElasticsearchQueryOrThrow(indicator.params.filter));
|
||||
}
|
||||
|
||||
const dataView = await this.getIndicatorDataView({
|
||||
dataViewService,
|
||||
dataViewId: indicator.params.dataViewId,
|
||||
});
|
||||
const dataView = await this.getIndicatorDataView(indicator.params.dataViewId);
|
||||
|
||||
return {
|
||||
index: SYNTHETICS_INDEX_PATTERN,
|
||||
runtime_mappings: this.buildCommonRuntimeMappings(slo, dataView),
|
||||
runtime_mappings: this.buildCommonRuntimeMappings(dataView),
|
||||
query: {
|
||||
bool: {
|
||||
filter: queryFilter,
|
||||
|
|
|
@ -5,18 +5,17 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { dataViewsService } from '@kbn/data-views-plugin/server/mocks';
|
||||
import { twoMinute } from '../fixtures/duration';
|
||||
import {
|
||||
createTimesliceMetricIndicator,
|
||||
createSLOWithTimeslicesBudgetingMethod,
|
||||
createSLO,
|
||||
createSLOWithTimeslicesBudgetingMethod,
|
||||
createTimesliceMetricIndicator,
|
||||
} from '../fixtures/slo';
|
||||
import { TimesliceMetricTransformGenerator } from './timeslice_metric';
|
||||
import { dataViewsService } from '@kbn/data-views-plugin/server/mocks';
|
||||
|
||||
const generator = new TimesliceMetricTransformGenerator();
|
||||
const spaceId = 'custom-space';
|
||||
|
||||
const SPACE_ID = 'custom-space';
|
||||
const generator = new TimesliceMetricTransformGenerator(SPACE_ID, dataViewsService);
|
||||
const everythingIndicator = createTimesliceMetricIndicator(
|
||||
[
|
||||
{ name: 'A', aggregation: 'avg', field: 'test.field', filter: 'test.category: "test"' },
|
||||
|
@ -38,7 +37,7 @@ describe('Timeslice Metric Transform Generator', () => {
|
|||
'(A / 200) + A'
|
||||
),
|
||||
});
|
||||
await expect(generator.getTransformParams(anSLO, spaceId, dataViewsService)).rejects.toThrow(
|
||||
await expect(generator.getTransformParams(anSLO)).rejects.toThrow(
|
||||
'The sli.metric.timeslice indicator MUST have a timeslice budgeting method.'
|
||||
);
|
||||
});
|
||||
|
@ -49,9 +48,7 @@ describe('Timeslice Metric Transform Generator', () => {
|
|||
'(a / 200) + A'
|
||||
),
|
||||
});
|
||||
await expect(generator.getTransformParams(anSLO, spaceId, dataViewsService)).rejects.toThrow(
|
||||
/Invalid equation/
|
||||
);
|
||||
await expect(generator.getTransformParams(anSLO)).rejects.toThrow(/Invalid equation/);
|
||||
});
|
||||
it('throws when the metric filter is invalid', async () => {
|
||||
const anSLO = createSLOWithTimeslicesBudgetingMethod({
|
||||
|
@ -60,9 +57,7 @@ describe('Timeslice Metric Transform Generator', () => {
|
|||
'(A / 200) + A'
|
||||
),
|
||||
});
|
||||
await expect(generator.getTransformParams(anSLO, spaceId, dataViewsService)).rejects.toThrow(
|
||||
/Invalid KQL: test:/
|
||||
);
|
||||
await expect(generator.getTransformParams(anSLO)).rejects.toThrow(/Invalid KQL: test:/);
|
||||
});
|
||||
it('throws when the query_filter is invalid', async () => {
|
||||
const anSLO = createSLOWithTimeslicesBudgetingMethod({
|
||||
|
@ -72,9 +67,7 @@ describe('Timeslice Metric Transform Generator', () => {
|
|||
'test:'
|
||||
),
|
||||
});
|
||||
await expect(generator.getTransformParams(anSLO, spaceId, dataViewsService)).rejects.toThrow(
|
||||
/Invalid KQL/
|
||||
);
|
||||
await expect(generator.getTransformParams(anSLO)).rejects.toThrow(/Invalid KQL/);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -83,7 +76,7 @@ describe('Timeslice Metric Transform Generator', () => {
|
|||
id: 'irrelevant',
|
||||
indicator: everythingIndicator,
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
});
|
||||
|
@ -93,7 +86,7 @@ describe('Timeslice Metric Transform Generator', () => {
|
|||
id: 'irrelevant',
|
||||
indicator: everythingIndicator,
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform).toMatchSnapshot();
|
||||
});
|
||||
|
@ -102,7 +95,7 @@ describe('Timeslice Metric Transform Generator', () => {
|
|||
const anSLO = createSLOWithTimeslicesBudgetingMethod({
|
||||
indicator: everythingIndicator,
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.source.query).toMatchSnapshot();
|
||||
});
|
||||
|
@ -114,7 +107,7 @@ describe('Timeslice Metric Transform Generator', () => {
|
|||
params: { ...everythingIndicator.params, index: 'my-own-index*' },
|
||||
},
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.source.index).toBe('my-own-index*');
|
||||
});
|
||||
|
@ -126,7 +119,7 @@ describe('Timeslice Metric Transform Generator', () => {
|
|||
params: { ...everythingIndicator.params, timestampField: 'my-date-field' },
|
||||
},
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.sync?.time?.field).toBe('my-date-field');
|
||||
// @ts-ignore
|
||||
|
@ -137,7 +130,7 @@ describe('Timeslice Metric Transform Generator', () => {
|
|||
const anSLO = createSLOWithTimeslicesBudgetingMethod({
|
||||
indicator: everythingIndicator,
|
||||
});
|
||||
const transform = await generator.getTransformParams(anSLO, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.pivot!.aggregations!._metric).toEqual({
|
||||
bucket_script: {
|
||||
|
@ -185,7 +178,7 @@ describe('Timeslice Metric Transform Generator', () => {
|
|||
},
|
||||
});
|
||||
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
const transform = await generator.getTransformParams(slo);
|
||||
|
||||
// @ts-ignore
|
||||
const rangeFilter = transform.source.query.bool.filter.find((f) => 'range' in f);
|
||||
|
|
|
@ -28,11 +28,11 @@ import { getFilterRange } from './common';
|
|||
const INVALID_EQUATION_REGEX = /[^A-Z|+|\-|\s|\d+|\.|\(|\)|\/|\*|>|<|=|\?|\:|&|\!|\|]+/g;
|
||||
|
||||
export class TimesliceMetricTransformGenerator extends TransformGenerator {
|
||||
public async getTransformParams(
|
||||
slo: SLODefinition,
|
||||
spaceId: string,
|
||||
dataViewService: DataViewsService
|
||||
): Promise<TransformPutTransformRequest> {
|
||||
constructor(spaceId: string, dataViewService: DataViewsService) {
|
||||
super(spaceId, dataViewService);
|
||||
}
|
||||
|
||||
public async getTransformParams(slo: SLODefinition): Promise<TransformPutTransformRequest> {
|
||||
if (!timesliceMetricIndicatorSchema.is(slo.indicator)) {
|
||||
throw new InvalidTransformError(`Cannot handle SLO of indicator type: ${slo.indicator.type}`);
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ export class TimesliceMetricTransformGenerator extends TransformGenerator {
|
|||
return getSLOTransformTemplate(
|
||||
this.buildTransformId(slo),
|
||||
this.buildDescription(slo),
|
||||
await this.buildSource(slo, slo.indicator, dataViewService),
|
||||
await this.buildSource(slo, slo.indicator),
|
||||
this.buildDestination(slo),
|
||||
this.buildCommonGroupBy(slo, slo.indicator.params.timestampField),
|
||||
this.buildAggregations(slo, slo.indicator),
|
||||
|
@ -53,18 +53,12 @@ export class TimesliceMetricTransformGenerator extends TransformGenerator {
|
|||
return getSLOTransformId(slo.id, slo.revision);
|
||||
}
|
||||
|
||||
private async buildSource(
|
||||
slo: SLODefinition,
|
||||
indicator: TimesliceMetricIndicator,
|
||||
dataViewService: DataViewsService
|
||||
) {
|
||||
const dataView = await this.getIndicatorDataView({
|
||||
dataViewService,
|
||||
dataViewId: indicator.params.index,
|
||||
});
|
||||
private async buildSource(slo: SLODefinition, indicator: TimesliceMetricIndicator) {
|
||||
const dataView = await this.getIndicatorDataView(indicator.params.dataViewId);
|
||||
|
||||
return {
|
||||
index: parseIndex(indicator.params.index),
|
||||
runtime_mappings: this.buildCommonRuntimeMappings(slo, dataView),
|
||||
runtime_mappings: this.buildCommonRuntimeMappings(dataView),
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
|
|
|
@ -7,50 +7,42 @@
|
|||
|
||||
import { createAPMTransactionErrorRateIndicator, createSLO } from '../fixtures/slo';
|
||||
import { ApmTransactionErrorRateTransformGenerator } from './apm_transaction_error_rate';
|
||||
import { dataViewsService } from '@kbn/data-views-plugin/server/mocks';
|
||||
|
||||
const generator = new ApmTransactionErrorRateTransformGenerator();
|
||||
const generator = new ApmTransactionErrorRateTransformGenerator('my-space-id', dataViewsService);
|
||||
|
||||
describe('Transform Generator', () => {
|
||||
it('builds empty runtime mappings without group by', async () => {
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
indicator: createAPMTransactionErrorRateIndicator(),
|
||||
});
|
||||
const commonRuntime = generator.buildCommonRuntimeMappings(slo);
|
||||
expect(commonRuntime).toMatchSnapshot();
|
||||
|
||||
const commonGroupBy = generator.buildCommonGroupBy(slo);
|
||||
expect(commonGroupBy).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it.each(['example', ['example']])(
|
||||
'builds common runtime mappings and group by with single group by',
|
||||
async (groupBy) => {
|
||||
const indicator = createAPMTransactionErrorRateIndicator();
|
||||
describe('buildCommonGroupBy', () => {
|
||||
it('builds empty runtime mappings without group by', async () => {
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
groupBy,
|
||||
indicator,
|
||||
indicator: createAPMTransactionErrorRateIndicator(),
|
||||
});
|
||||
const commonRuntime = generator.buildCommonRuntimeMappings(slo);
|
||||
expect(commonRuntime).toMatchSnapshot();
|
||||
|
||||
const commonGroupBy = generator.buildCommonGroupBy(slo);
|
||||
expect(commonGroupBy).toMatchSnapshot();
|
||||
}
|
||||
);
|
||||
|
||||
it('builds common runtime mappings without multi group by', async () => {
|
||||
const indicator = createAPMTransactionErrorRateIndicator();
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
groupBy: ['example1', 'example2'],
|
||||
indicator,
|
||||
});
|
||||
const commonRuntime = generator.buildCommonRuntimeMappings(slo);
|
||||
expect(commonRuntime).toMatchSnapshot();
|
||||
|
||||
const commonGroupBy = generator.buildCommonGroupBy(slo);
|
||||
expect(commonGroupBy).toMatchSnapshot();
|
||||
it.each(['example', ['example'], ['example1', 'example2']])(
|
||||
'builds common groupBy with single group by',
|
||||
async (groupBy) => {
|
||||
const indicator = createAPMTransactionErrorRateIndicator();
|
||||
const slo = createSLO({
|
||||
id: 'irrelevant',
|
||||
groupBy,
|
||||
indicator,
|
||||
});
|
||||
|
||||
const commonGroupBy = generator.buildCommonGroupBy(slo);
|
||||
expect(commonGroupBy).toMatchSnapshot();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('buildCommonRuntimeMappings', () => {
|
||||
it('builds empty runtime mappings without data view', async () => {
|
||||
const runtimeMappings = generator.buildCommonRuntimeMappings();
|
||||
expect(runtimeMappings).toEqual({});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,23 +9,22 @@ import {
|
|||
MappingRuntimeFields,
|
||||
TransformPutTransformRequest,
|
||||
} from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { ALL_VALUE, timeslicesBudgetingMethodSchema } from '@kbn/slo-schema';
|
||||
import { DataView, DataViewsService } from '@kbn/data-views-plugin/common';
|
||||
import { ALL_VALUE, timeslicesBudgetingMethodSchema } from '@kbn/slo-schema';
|
||||
import { TransformSettings } from '../../assets/transform_templates/slo_transform_template';
|
||||
import { SLODefinition } from '../../domain/models';
|
||||
|
||||
export abstract class TransformGenerator {
|
||||
public abstract getTransformParams(
|
||||
slo: SLODefinition,
|
||||
spaceId: string,
|
||||
dataViewService: DataViewsService,
|
||||
isServerless: boolean
|
||||
): Promise<TransformPutTransformRequest>;
|
||||
constructor(
|
||||
protected spaceId: string,
|
||||
protected dataViewService: DataViewsService,
|
||||
protected isServerless: boolean = false
|
||||
) {}
|
||||
|
||||
public buildCommonRuntimeMappings(slo: SLODefinition, dataView?: DataView): MappingRuntimeFields {
|
||||
return {
|
||||
...(dataView?.getRuntimeMappings?.() ?? {}),
|
||||
};
|
||||
public abstract getTransformParams(slo: SLODefinition): Promise<TransformPutTransformRequest>;
|
||||
|
||||
public buildCommonRuntimeMappings(dataView?: DataView): MappingRuntimeFields {
|
||||
return dataView?.getRuntimeMappings?.() ?? {};
|
||||
}
|
||||
|
||||
public buildDescription(slo: SLODefinition): string {
|
||||
|
@ -71,17 +70,11 @@ export abstract class TransformGenerator {
|
|||
};
|
||||
}
|
||||
|
||||
public async getIndicatorDataView({
|
||||
dataViewService,
|
||||
dataViewId,
|
||||
}: {
|
||||
dataViewService: DataViewsService;
|
||||
dataViewId?: string;
|
||||
}): Promise<DataView | undefined> {
|
||||
public async getIndicatorDataView(dataViewId?: string): Promise<DataView | undefined> {
|
||||
let dataView: DataView | undefined;
|
||||
if (dataViewId) {
|
||||
try {
|
||||
dataView = await dataViewService.get(dataViewId);
|
||||
dataView = await this.dataViewService.get(dataViewId);
|
||||
} catch (e) {
|
||||
// If the data view is not found, we will continue without it
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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 { DataViewsService } from '@kbn/data-views-plugin/server';
|
||||
import {
|
||||
ApmTransactionDurationTransformGenerator,
|
||||
ApmTransactionErrorRateTransformGenerator,
|
||||
HistogramTransformGenerator,
|
||||
KQLCustomTransformGenerator,
|
||||
MetricCustomTransformGenerator,
|
||||
SyntheticsAvailabilityTransformGenerator,
|
||||
TimesliceMetricTransformGenerator,
|
||||
TransformGenerator,
|
||||
} from '.';
|
||||
import { IndicatorTypes } from '../../domain/models';
|
||||
|
||||
export function createTransformGenerators(
|
||||
spaceId: string,
|
||||
dataViewsService: DataViewsService,
|
||||
isServerless: boolean
|
||||
): Record<IndicatorTypes, TransformGenerator> {
|
||||
return {
|
||||
'sli.apm.transactionDuration': new ApmTransactionDurationTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService
|
||||
),
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService
|
||||
),
|
||||
'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),
|
||||
};
|
||||
}
|
|
@ -44,15 +44,12 @@ describe('TransformManager', () => {
|
|||
it('throws when no generator exists for the slo indicator type', async () => {
|
||||
// @ts-ignore defining only a subset of the possible SLI
|
||||
const generators: Record<IndicatorTypes, TransformGenerator> = {
|
||||
'sli.apm.transactionDuration': new DummyTransformGenerator(),
|
||||
'sli.apm.transactionDuration': new DummyTransformGenerator(spaceId, dataViewsService),
|
||||
};
|
||||
const service = new DefaultTransformManager(
|
||||
generators,
|
||||
scopedClusterClientMock,
|
||||
loggerMock,
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
false
|
||||
loggerMock
|
||||
);
|
||||
|
||||
await expect(
|
||||
|
@ -63,15 +60,12 @@ describe('TransformManager', () => {
|
|||
it('throws when transform generator fails', async () => {
|
||||
// @ts-ignore defining only a subset of the possible SLI
|
||||
const generators: Record<IndicatorTypes, TransformGenerator> = {
|
||||
'sli.apm.transactionDuration': new FailTransformGenerator(),
|
||||
'sli.apm.transactionDuration': new FailTransformGenerator(spaceId, dataViewsService),
|
||||
};
|
||||
const transformManager = new DefaultTransformManager(
|
||||
generators,
|
||||
scopedClusterClientMock,
|
||||
loggerMock,
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
false
|
||||
loggerMock
|
||||
);
|
||||
|
||||
await expect(
|
||||
|
@ -85,15 +79,15 @@ describe('TransformManager', () => {
|
|||
it('installs the transform', async () => {
|
||||
// @ts-ignore defining only a subset of the possible SLI
|
||||
const generators: Record<IndicatorTypes, TransformGenerator> = {
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(),
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService
|
||||
),
|
||||
};
|
||||
const transformManager = new DefaultTransformManager(
|
||||
generators,
|
||||
scopedClusterClientMock,
|
||||
loggerMock,
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
false
|
||||
loggerMock
|
||||
);
|
||||
const slo = createSLO({ indicator: createAPMTransactionErrorRateIndicator() });
|
||||
|
||||
|
@ -110,15 +104,15 @@ describe('TransformManager', () => {
|
|||
it('previews the transform', async () => {
|
||||
// @ts-ignore defining only a subset of the possible SLI
|
||||
const generators: Record<IndicatorTypes, TransformGenerator> = {
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(),
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService
|
||||
),
|
||||
};
|
||||
const transformManager = new DefaultTransformManager(
|
||||
generators,
|
||||
scopedClusterClientMock,
|
||||
loggerMock,
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
false
|
||||
loggerMock
|
||||
);
|
||||
|
||||
await transformManager.preview('slo-transform-id');
|
||||
|
@ -133,15 +127,15 @@ describe('TransformManager', () => {
|
|||
it('starts the transform', async () => {
|
||||
// @ts-ignore defining only a subset of the possible SLI
|
||||
const generators: Record<IndicatorTypes, TransformGenerator> = {
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(),
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService
|
||||
),
|
||||
};
|
||||
const transformManager = new DefaultTransformManager(
|
||||
generators,
|
||||
scopedClusterClientMock,
|
||||
loggerMock,
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
false
|
||||
loggerMock
|
||||
);
|
||||
|
||||
await transformManager.start('slo-transform-id');
|
||||
|
@ -156,15 +150,15 @@ describe('TransformManager', () => {
|
|||
it('stops the transform', async () => {
|
||||
// @ts-ignore defining only a subset of the possible SLI
|
||||
const generators: Record<IndicatorTypes, TransformGenerator> = {
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(),
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService
|
||||
),
|
||||
};
|
||||
const transformManager = new DefaultTransformManager(
|
||||
generators,
|
||||
scopedClusterClientMock,
|
||||
loggerMock,
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
false
|
||||
loggerMock
|
||||
);
|
||||
|
||||
await transformManager.stop('slo-transform-id');
|
||||
|
@ -179,15 +173,15 @@ describe('TransformManager', () => {
|
|||
it('uninstalls the transform', async () => {
|
||||
// @ts-ignore defining only a subset of the possible SLI
|
||||
const generators: Record<IndicatorTypes, TransformGenerator> = {
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(),
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService
|
||||
),
|
||||
};
|
||||
const transformManager = new DefaultTransformManager(
|
||||
generators,
|
||||
scopedClusterClientMock,
|
||||
loggerMock,
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
false
|
||||
loggerMock
|
||||
);
|
||||
|
||||
await transformManager.uninstall('slo-transform-id');
|
||||
|
@ -203,15 +197,15 @@ describe('TransformManager', () => {
|
|||
);
|
||||
// @ts-ignore defining only a subset of the possible SLI
|
||||
const generators: Record<IndicatorTypes, TransformGenerator> = {
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(),
|
||||
'sli.apm.transactionErrorRate': new ApmTransactionErrorRateTransformGenerator(
|
||||
spaceId,
|
||||
dataViewsService
|
||||
),
|
||||
};
|
||||
const transformManager = new DefaultTransformManager(
|
||||
generators,
|
||||
scopedClusterClientMock,
|
||||
loggerMock,
|
||||
spaceId,
|
||||
dataViewsService,
|
||||
false
|
||||
loggerMock
|
||||
);
|
||||
|
||||
await transformManager.uninstall('slo-transform-id');
|
||||
|
@ -224,21 +218,20 @@ describe('TransformManager', () => {
|
|||
});
|
||||
|
||||
class DummyTransformGenerator extends TransformGenerator {
|
||||
async getTransformParams(
|
||||
slo: SLODefinition,
|
||||
spaceId: string,
|
||||
dataViewService: DataViewsService
|
||||
): Promise<TransformPutTransformRequest> {
|
||||
constructor(spaceId: string, dataViewService: DataViewsService) {
|
||||
super(spaceId, dataViewService);
|
||||
}
|
||||
async getTransformParams(slo: SLODefinition): Promise<TransformPutTransformRequest> {
|
||||
return {} as TransformPutTransformRequest;
|
||||
}
|
||||
}
|
||||
|
||||
class FailTransformGenerator extends TransformGenerator {
|
||||
getTransformParams(
|
||||
slo: SLODefinition,
|
||||
spaceId: string,
|
||||
dataViewService: DataViewsService
|
||||
): Promise<TransformPutTransformRequest> {
|
||||
constructor(spaceId: string, dataViewService: DataViewsService) {
|
||||
super(spaceId, dataViewService);
|
||||
}
|
||||
|
||||
getTransformParams(slo: SLODefinition): Promise<TransformPutTransformRequest> {
|
||||
throw new Error('Some error');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { IScopedClusterClient, Logger } from '@kbn/core/server';
|
||||
|
||||
import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { DataViewsService } from '@kbn/data-views-plugin/server';
|
||||
import { SLODefinition, IndicatorTypes } from '../domain/models';
|
||||
import { IScopedClusterClient, Logger } from '@kbn/core/server';
|
||||
import { IndicatorTypes, SLODefinition } from '../domain/models';
|
||||
import { SecurityException } from '../errors';
|
||||
import { retryTransientEsErrors } from '../utils/retry';
|
||||
import { TransformGenerator } from './transform_generators';
|
||||
|
@ -29,10 +27,7 @@ export class DefaultTransformManager implements TransformManager {
|
|||
constructor(
|
||||
private generators: Record<IndicatorTypes, TransformGenerator>,
|
||||
private scopedClusterClient: IScopedClusterClient,
|
||||
private logger: Logger,
|
||||
private spaceId: string,
|
||||
private dataViewService: DataViewsService,
|
||||
private isServerless: boolean
|
||||
private logger: Logger
|
||||
) {}
|
||||
|
||||
async install(slo: SLODefinition): Promise<TransformId> {
|
||||
|
@ -42,12 +37,7 @@ export class DefaultTransformManager implements TransformManager {
|
|||
throw new Error(`Unsupported indicator type [${slo.indicator.type}]`);
|
||||
}
|
||||
|
||||
const transformParams = await generator.getTransformParams(
|
||||
slo,
|
||||
this.spaceId,
|
||||
this.dataViewService,
|
||||
this.isServerless
|
||||
);
|
||||
const transformParams = await generator.getTransformParams(slo);
|
||||
try {
|
||||
await retryTransientEsErrors(
|
||||
() => this.scopedClusterClient.asSecondaryAuthUser.transform.putTransform(transformParams),
|
||||
|
@ -74,12 +64,7 @@ export class DefaultTransformManager implements TransformManager {
|
|||
throw new Error(`Unsupported indicator type [${slo.indicator.type}]`);
|
||||
}
|
||||
|
||||
return await generator.getTransformParams(
|
||||
slo,
|
||||
this.spaceId,
|
||||
this.dataViewService,
|
||||
this.isServerless
|
||||
);
|
||||
return await generator.getTransformParams(slo);
|
||||
}
|
||||
|
||||
async preview(transformId: string): Promise<void> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue