[SLO] Use enrich policy to add SLO details to summary (#169993)

## 🍒 Summary

This is a PR for #169728, it refactors the transforms to use an enrich
policy to inject fields from the SLO definition in the ingest pipeline
for both the SLI and summary indices. I also added the `event.ingested`
field to the SLI data to see how that would work with the summary
transform.

### 🐰 Prerequisites

https://github.com/elastic/elasticsearch/pull/101682

Fixes #169956
Fixes #166687
Fixes #166955
Fixes #169728

---------

Co-authored-by: Kevin Delemme <kevin.delemme@elastic.co>
This commit is contained in:
Chris Cowan 2023-11-15 14:09:39 -07:00 committed by GitHub
parent 46322cee6d
commit 089dd18a35
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 682 additions and 1939 deletions

View file

@ -58,6 +58,7 @@ export const PoliciesTable: FunctionComponent<Props> = ({
fill
iconType="plusInCircle"
{...reactRouterNavigate(history, '/enrich_policies/create')}
data-test-subj="enrichPoliciesPoliciesTableCreateButton"
>
<FormattedMessage
id="xpack.idxMgmt.enrichPolicies.table.createPolicyButton"

View file

@ -555,7 +555,7 @@ export function useLensDefinition(slo: SLOResponse): TypedLensByValueInput['attr
adHocDataViews: {
'32ca1ad4-81c0-4daf-b9d1-07118044bdc5': {
id: '32ca1ad4-81c0-4daf-b9d1-07118044bdc5',
title: '.slo-observability.sli-v2.*',
title: '.slo-observability.sli-v3.*',
timeFieldName: '@timestamp',
sourceFilters: [],
fieldFormats: {},

View file

@ -12,6 +12,14 @@ export const getSLOMappingsTemplate = (name: string) => ({
template: {
mappings: {
properties: {
event: {
properties: {
ingested: {
type: 'date',
format: 'strict_date_optional_time',
},
},
},
'@timestamp': {
type: 'date',
format: 'date_optional_time||epoch_millis',
@ -50,34 +58,10 @@ export const getSLOMappingsTemplate = (name: string) => ({
revision: {
type: 'long',
},
groupBy: {
type: 'keyword',
ignore_above: 256,
},
instanceId: {
type: 'keyword',
ignore_above: 256,
},
name: {
type: 'keyword',
ignore_above: 256,
},
description: {
type: 'keyword',
ignore_above: 256,
},
tags: {
type: 'keyword',
ignore_above: 256,
},
indicator: {
properties: {
type: {
type: 'keyword',
ignore_above: 256,
},
},
},
objective: {
properties: {
target: {

View file

@ -55,12 +55,10 @@ export const getSLOSummaryMappingsTemplate = (name: string) => ({
ignore_above: 256,
},
name: {
type: 'keyword',
ignore_above: 256,
type: 'text',
},
description: {
type: 'keyword',
ignore_above: 256,
type: 'text',
},
tags: {
type: 'keyword',
@ -120,6 +118,14 @@ export const getSLOSummaryMappingsTemplate = (name: string) => ({
isTempDoc: {
type: 'boolean',
},
latestSliTimestamp: {
type: 'date',
format: 'date_optional_time||epoch_millis',
},
summaryUpdatedAt: {
type: 'date',
format: 'date_optional_time||epoch_millis',
},
},
},
},

View file

@ -4,9 +4,8 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export const SLO_RESOURCES_VERSION = 2;
export const SLO_SUMMARY_TRANSFORMS_VERSION = 3;
export const SLO_RESOURCES_VERSION = 3;
export const SLO_SUMMARY_TRANSFORMS_VERSION = 4;
export const SLO_COMPONENT_TEMPLATE_MAPPINGS_NAME = '.slo-observability.sli-mappings';
export const SLO_COMPONENT_TEMPLATE_SETTINGS_NAME = '.slo-observability.sli-settings';
@ -32,6 +31,7 @@ export const SLO_SUMMARY_TEMP_INDEX_NAME = `.slo-observability.summary-v${SLO_RE
export const SLO_SUMMARY_DESTINATION_INDEX_PATTERN = `.slo-observability.summary-v${SLO_RESOURCES_VERSION}*`; // include temp and non-temp summary indices
export const SLO_SUMMARY_INGEST_PIPELINE_NAME = `.slo-observability.summary.pipeline`;
export const SLO_SUMMARY_ENRICH_POLICY_NAME = `slo-observability.summary.enrich_policy`;
export const getSLOTransformId = (sloId: string, sloRevision: number) =>
`slo-${sloId}-${sloRevision}`;

View file

@ -0,0 +1,39 @@
/*
* 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 { SO_SLO_TYPE } from '../../saved_objects';
import { SLO_SUMMARY_ENRICH_POLICY_NAME } from '../constants';
export const getSLOSummaryEnrichPolicy = () => ({
name: SLO_SUMMARY_ENRICH_POLICY_NAME,
match: {
indices: '.kibana',
match_field: 'slo.id',
enrich_fields: [
'slo.name',
'slo.description',
'slo.tags',
'slo.indicator.type',
'slo.objective.target',
'slo.budgetingMethod',
'slo.timeWindow.type',
'slo.timeWindow.duration',
'slo.groupBy',
],
query: {
bool: {
filter: [
{
match_phrase: {
type: SO_SLO_TYPE,
},
},
],
},
},
},
});

View file

@ -5,12 +5,48 @@
* 2.0.
*/
import { SLO_RESOURCES_VERSION } from '../constants';
import { SLO_RESOURCES_VERSION, SLO_SUMMARY_ENRICH_POLICY_NAME } from '../constants';
export const getSLOPipelineTemplate = (id: string, indexNamePrefix: string) => ({
id,
description: 'Monthly date-time index naming for SLO data',
processors: [
{
enrich: {
field: 'slo.id',
policy_name: SLO_SUMMARY_ENRICH_POLICY_NAME,
target_field: '_enrich',
},
},
{
set: {
field: 'slo.timeWindow',
copy_from: '_enrich.slo.timeWindow',
},
},
{
set: {
field: 'slo.budgetingMethod',
copy_from: '_enrich.slo.budgetingMethod',
},
},
{
set: {
field: 'slo.objective.target',
copy_from: '_enrich.slo.objective.target',
},
},
{
remove: {
field: '_enrich',
},
},
{
set: {
field: 'event.ingested',
value: '{{{_ingest.timestamp}}}',
},
},
{
date_index_name: {
field: '@timestamp',

View file

@ -5,19 +5,12 @@
* 2.0.
*/
import { SLO_RESOURCES_VERSION } from '../constants';
import { SLO_RESOURCES_VERSION, SLO_SUMMARY_ENRICH_POLICY_NAME } from '../constants';
export const getSLOSummaryPipelineTemplate = (id: string) => ({
id,
description: 'SLO summary ingest pipeline',
processors: [
{
split: {
description: 'Split comma separated list of tags into an array',
field: 'slo.tags',
separator: ',',
},
},
{
set: {
description: "if 'statusCode == 0', set status to NO_DATA",
@ -50,6 +43,72 @@ export const getSLOSummaryPipelineTemplate = (id: string) => ({
value: 'HEALTHY',
},
},
{
enrich: {
field: 'slo.id',
policy_name: SLO_SUMMARY_ENRICH_POLICY_NAME,
target_field: '_enrich',
},
},
{
set: {
field: 'slo.name',
copy_from: '_enrich.slo.name',
},
},
{
set: {
field: 'slo.description',
copy_from: '_enrich.slo.description',
},
},
{
set: {
field: 'slo.indicator',
copy_from: '_enrich.slo.indicator',
},
},
{
set: {
field: 'slo.timeWindow',
copy_from: '_enrich.slo.timeWindow',
},
},
{
set: {
field: 'slo.groupBy',
copy_from: '_enrich.slo.groupBy',
},
},
{
set: {
field: 'slo.tags',
copy_from: '_enrich.slo.tags',
},
},
{
set: {
field: 'slo.objective',
copy_from: '_enrich.slo.objective',
},
},
{
set: {
field: 'slo.budgetingMethod',
copy_from: '_enrich.slo.budgetingMethod',
},
},
{
remove: {
field: '_enrich',
},
},
{
set: {
field: 'summaryUpdatedAt',
value: '{{{_ingest.timestamp}}}',
},
},
],
_meta: {
description: 'SLO summary ingest pipeline',

View file

@ -83,10 +83,11 @@ const createSLORoute = createObservabilityServerRoute({
await assertPlatinumLicense(context);
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const systemEsClient = (await context.core).elasticsearch.client.asInternalUser;
const soClient = (await context.core).savedObjects.client;
const repository = new KibanaSavedObjectsSLORepository(soClient);
const transformManager = new DefaultTransformManager(transformGenerators, esClient, logger);
const createSLO = new CreateSLO(esClient, repository, transformManager);
const createSLO = new CreateSLO(esClient, systemEsClient, repository, transformManager);
const response = await createSLO.execute(params.body);
@ -105,11 +106,12 @@ const updateSLORoute = createObservabilityServerRoute({
await assertPlatinumLicense(context);
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const systemEsClient = (await context.core).elasticsearch.client.asInternalUser;
const soClient = (await context.core).savedObjects.client;
const repository = new KibanaSavedObjectsSLORepository(soClient);
const transformManager = new DefaultTransformManager(transformGenerators, esClient, logger);
const updateSLO = new UpdateSLO(repository, transformManager, esClient);
const updateSLO = new UpdateSLO(repository, transformManager, esClient, systemEsClient);
const response = await updateSLO.execute(params.path.id, params.body);
@ -134,13 +136,20 @@ const deleteSLORoute = createObservabilityServerRoute({
await assertPlatinumLicense(context);
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const systemEsClient = (await context.core).elasticsearch.client.asInternalUser;
const soClient = (await context.core).savedObjects.client;
const rulesClient = getRulesClientWithRequest(request);
const repository = new KibanaSavedObjectsSLORepository(soClient);
const transformManager = new DefaultTransformManager(transformGenerators, esClient, logger);
const deleteSLO = new DeleteSLO(repository, transformManager, esClient, rulesClient);
const deleteSLO = new DeleteSLO(
repository,
transformManager,
esClient,
rulesClient,
systemEsClient
);
await deleteSLO.execute(params.path.id);
},

View file

@ -41,8 +41,16 @@ Array [
},
},
"id": "slo-unique-id",
"index": ".slo-observability.summary-v2.temp",
"index": ".slo-observability.summary-v3.temp",
"refresh": true,
},
]
`;
exports[`CreateSLO happy path calls the expected services 2`] = `
Array [
Object {
"name": "slo-observability.summary.enrich_policy",
},
]
`;

View file

@ -11,7 +11,7 @@ Array [
},
},
},
"index": ".slo-observability.sli-v2*",
"index": ".slo-observability.sli-v3*",
"query": Object {
"bool": Object {
"filter": Array [

View file

@ -3,7 +3,7 @@
exports[`Summary Search Client returns the summary documents without duplicate temporary summary documents 1`] = `
Array [
Object {
"index": ".slo-observability.summary-v2*",
"index": ".slo-observability.summary-v3*",
"query": Object {
"bool": Object {
"filter": Array [

View file

@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`UpdateSLO index a temporary summary document 1`] = `
exports[`UpdateSLO when the revision bumps indexes a temporary summary document 1`] = `
Array [
Object {
"document": Object {
@ -44,7 +44,7 @@ Array [
},
},
"id": "slo-unique-id",
"index": ".slo-observability.summary-v2.temp",
"index": ".slo-observability.summary-v3.temp",
"refresh": true,
},
]

View file

@ -15,15 +15,22 @@ import { TransformManager } from './transform_manager';
describe('CreateSLO', () => {
let esClientMock: ElasticsearchClientMock;
let esSystemClientMock: ElasticsearchClientMock;
let mockRepository: jest.Mocked<SLORepository>;
let mockTransformManager: jest.Mocked<TransformManager>;
let createSLO: CreateSLO;
beforeEach(() => {
esClientMock = elasticsearchServiceMock.createElasticsearchClient();
esSystemClientMock = elasticsearchServiceMock.createElasticsearchClient();
mockRepository = createSLORepositoryMock();
mockTransformManager = createTransformManagerMock();
createSLO = new CreateSLO(esClientMock, mockRepository, mockTransformManager);
createSLO = new CreateSLO(
esClientMock,
esSystemClientMock,
mockRepository,
mockTransformManager
);
});
describe('happy path', () => {
@ -59,6 +66,7 @@ describe('CreateSLO', () => {
expect(mockTransformManager.start).toHaveBeenCalledWith('slo-transform-id');
expect(response).toEqual(expect.objectContaining({ id: 'unique-id' }));
expect(esClientMock.index.mock.calls[0]).toMatchSnapshot();
expect(esSystemClientMock.enrich.executePolicy.mock.calls[0]).toMatchSnapshot();
});
it('overrides the default values when provided', async () => {

View file

@ -8,7 +8,10 @@
import { ElasticsearchClient } from '@kbn/core/server';
import { ALL_VALUE, CreateSLOParams, CreateSLOResponse } from '@kbn/slo-schema';
import { v4 as uuidv4 } from 'uuid';
import { SLO_SUMMARY_TEMP_INDEX_NAME } from '../../assets/constants';
import {
SLO_SUMMARY_ENRICH_POLICY_NAME,
SLO_SUMMARY_TEMP_INDEX_NAME,
} from '../../assets/constants';
import { Duration, DurationUnit, SLO } from '../../domain/models';
import { validateSLO } from '../../domain/services';
import { SLORepository } from './slo_repository';
@ -18,6 +21,7 @@ import { TransformManager } from './transform_manager';
export class CreateSLO {
constructor(
private esClient: ElasticsearchClient,
private systemClient: ElasticsearchClient,
private repository: SLORepository,
private transformManager: TransformManager
) {}
@ -54,6 +58,8 @@ export class CreateSLO {
refresh: true,
});
await this.systemClient.enrich.executePolicy({ name: SLO_SUMMARY_ENRICH_POLICY_NAME });
return this.toResponse(slo);
}

View file

@ -24,6 +24,7 @@ describe('DeleteSLO', () => {
let mockRepository: jest.Mocked<SLORepository>;
let mockTransformManager: jest.Mocked<TransformManager>;
let mockEsClient: jest.Mocked<ElasticsearchClient>;
let mockSystemEsClient: jest.Mocked<ElasticsearchClient>;
let mockRulesClient: jest.Mocked<RulesClientApi>;
let deleteSLO: DeleteSLO;
@ -31,8 +32,15 @@ describe('DeleteSLO', () => {
mockRepository = createSLORepositoryMock();
mockTransformManager = createTransformManagerMock();
mockEsClient = elasticsearchServiceMock.createElasticsearchClient();
mockSystemEsClient = elasticsearchServiceMock.createElasticsearchClient();
mockRulesClient = rulesClientMock.create();
deleteSLO = new DeleteSLO(mockRepository, mockTransformManager, mockEsClient, mockRulesClient);
deleteSLO = new DeleteSLO(
mockRepository,
mockTransformManager,
mockEsClient,
mockRulesClient,
mockSystemEsClient
);
});
describe('happy path', () => {
@ -72,6 +80,7 @@ describe('DeleteSLO', () => {
},
})
);
expect(mockSystemEsClient.enrich.executePolicy).toHaveBeenCalled();
expect(mockRulesClient.bulkDeleteRules).toHaveBeenCalledWith({
filter: `alert.attributes.params.sloId:${slo.id}`,
});

View file

@ -11,6 +11,7 @@ import {
getSLOTransformId,
SLO_DESTINATION_INDEX_PATTERN,
SLO_SUMMARY_DESTINATION_INDEX_PATTERN,
SLO_SUMMARY_ENRICH_POLICY_NAME,
} from '../../assets/constants';
import { SLORepository } from './slo_repository';
import { TransformManager } from './transform_manager';
@ -20,7 +21,8 @@ export class DeleteSLO {
private repository: SLORepository,
private transformManager: TransformManager,
private esClient: ElasticsearchClient,
private rulesClient: RulesClientApi
private rulesClient: RulesClientApi,
private systemClient: ElasticsearchClient
) {}
public async execute(sloId: string): Promise<void> {
@ -34,6 +36,7 @@ export class DeleteSLO {
await this.deleteSummaryData(slo.id);
await this.deleteAssociatedRules(slo.id);
await this.repository.deleteById(slo.id);
await this.systemClient.enrich.executePolicy({ name: SLO_SUMMARY_ENRICH_POLICY_NAME });
}
private async deleteRollupData(sloId: string): Promise<void> {

View file

@ -43,7 +43,7 @@ describe('DeleteSLOInstances', () => {
expect(mockEsClient.deleteByQuery).toHaveBeenCalledTimes(2);
expect(mockEsClient.deleteByQuery.mock.calls[0][0]).toMatchInlineSnapshot(`
Object {
"index": ".slo-observability.sli-v2*",
"index": ".slo-observability.sli-v3*",
"query": Object {
"bool": Object {
"should": Array [
@ -103,7 +103,7 @@ describe('DeleteSLOInstances', () => {
`);
expect(mockEsClient.deleteByQuery.mock.calls[1][0]).toMatchInlineSnapshot(`
Object {
"index": ".slo-observability.summary-v2*",
"index": ".slo-observability.summary-v3*",
"query": Object {
"bool": Object {
"should": Array [

View file

@ -14,15 +14,20 @@ import {
SLO_INGEST_PIPELINE_NAME,
SLO_SUMMARY_COMPONENT_TEMPLATE_MAPPINGS_NAME,
SLO_SUMMARY_COMPONENT_TEMPLATE_SETTINGS_NAME,
SLO_SUMMARY_ENRICH_POLICY_NAME,
SLO_SUMMARY_INDEX_TEMPLATE_NAME,
SLO_SUMMARY_INGEST_PIPELINE_NAME,
} from '../../assets/constants';
import { getSLOSummaryEnrichPolicy } from '../../assets/enrich_policies/slo_summary_enrich_policy';
import { DefaultResourceInstaller } from './resource_installer';
describe('resourceInstaller', () => {
it('installs the common resources', async () => {
const mockClusterClient = elasticsearchServiceMock.createElasticsearchClient();
mockClusterClient.indices.getIndexTemplate.mockResponseOnce({ index_templates: [] });
mockClusterClient.enrich.getPolicy.mockResponseOnce({
policies: [],
});
const installer = new DefaultResourceInstaller(mockClusterClient, loggerMock.create());
await installer.ensureCommonResourcesInstalled();
@ -54,6 +59,21 @@ describe('resourceInstaller', () => {
expect.objectContaining({ name: SLO_SUMMARY_INDEX_TEMPLATE_NAME })
);
expect(mockClusterClient.enrich.getPolicy).toHaveBeenCalledTimes(1);
expect(mockClusterClient.enrich.getPolicy).toHaveBeenNthCalledWith(1, {
name: SLO_SUMMARY_ENRICH_POLICY_NAME,
});
expect(mockClusterClient.enrich.putPolicy).toHaveBeenCalledTimes(1);
expect(mockClusterClient.enrich.putPolicy).toHaveBeenNthCalledWith(
1,
getSLOSummaryEnrichPolicy()
);
expect(mockClusterClient.enrich.executePolicy).toHaveBeenCalledTimes(1);
expect(mockClusterClient.enrich.executePolicy).toHaveBeenNthCalledWith(1, {
name: SLO_SUMMARY_ENRICH_POLICY_NAME,
});
expect(mockClusterClient.ingest.putPipeline).toHaveBeenCalledTimes(2);
expect(mockClusterClient.ingest.putPipeline).toHaveBeenNthCalledWith(
1,
@ -64,4 +84,34 @@ describe('resourceInstaller', () => {
expect.objectContaining({ id: SLO_SUMMARY_INGEST_PIPELINE_NAME })
);
});
it('skips installing the enrich policy if it exists', async () => {
const mockClusterClient = elasticsearchServiceMock.createElasticsearchClient();
mockClusterClient.indices.getIndexTemplate.mockResponseOnce({ index_templates: [] });
mockClusterClient.enrich.getPolicy.mockResponseOnce({
policies: [
{
config: {
// Sigh.... the Elasticsarch type for an enrich policy has defined the
// query as a string which is completely wrong, it's a QueryDSLContainer!
//
// See: https://github.com/elastic/elasticsearch-js/issues/2074
match: {
...getSLOSummaryEnrichPolicy().match,
name: SLO_SUMMARY_ENRICH_POLICY_NAME,
} as any,
},
},
],
});
const installer = new DefaultResourceInstaller(mockClusterClient, loggerMock.create());
await installer.ensureCommonResourcesInstalled();
expect(mockClusterClient.enrich.getPolicy).toHaveBeenCalledTimes(1);
expect(mockClusterClient.enrich.getPolicy).toHaveBeenNthCalledWith(1, {
name: SLO_SUMMARY_ENRICH_POLICY_NAME,
});
expect(mockClusterClient.enrich.putPolicy).not.toHaveBeenCalled();
expect(mockClusterClient.enrich.executePolicy).not.toHaveBeenCalled();
});
});

View file

@ -7,6 +7,7 @@
import type {
ClusterPutComponentTemplateRequest,
EnrichPutPolicyRequest,
IndicesPutIndexTemplateRequest,
IngestPutPipelineRequest,
} from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
@ -31,6 +32,7 @@ import {
SLO_SUMMARY_INGEST_PIPELINE_NAME,
SLO_SUMMARY_TEMP_INDEX_NAME,
} from '../../assets/constants';
import { getSLOSummaryEnrichPolicy } from '../../assets/enrich_policies/slo_summary_enrich_policy';
import { getSLOIndexTemplate } from '../../assets/index_templates/slo_index_templates';
import { getSLOSummaryIndexTemplate } from '../../assets/index_templates/slo_summary_index_templates';
import { getSLOPipelineTemplate } from '../../assets/ingest_templates/slo_pipeline_template';
@ -84,6 +86,8 @@ export class DefaultResourceInstaller implements ResourceInstaller {
await this.createIndex(SLO_SUMMARY_DESTINATION_INDEX_NAME);
await this.createIndex(SLO_SUMMARY_TEMP_INDEX_NAME);
await this.createOrUpdateEnrichPolicy(getSLOSummaryEnrichPolicy());
await this.createOrUpdateIngestPipelineTemplate(
getSLOPipelineTemplate(SLO_INGEST_PIPELINE_NAME, SLO_INGEST_PIPELINE_INDEX_NAME_PREFIX)
);
@ -112,6 +116,20 @@ export class DefaultResourceInstaller implements ResourceInstaller {
return this.execute(() => this.esClient.ingest.putPipeline(template));
}
private async createOrUpdateEnrichPolicy(policy: EnrichPutPolicyRequest) {
return this.execute(async () => {
const existingPolicy = await this.esClient.enrich.getPolicy({ name: policy.name });
if (existingPolicy.policies.some(({ config }) => config.match?.name === policy.name)) {
this.logger.info(`SLO summary erich policy [${policy.name}] already exists.`);
return;
}
this.logger.info(`Installing SLO summary erich policy [${policy.name}]`);
return this.esClient.enrich
.putPolicy(policy)
.then(() => this.esClient.enrich.executePolicy({ name: policy.name }));
});
}
private async createIndex(indexName: string) {
try {
await this.execute(() => this.esClient.indices.create({ index: indexName }));

View file

@ -7,11 +7,11 @@ Array [
"_meta": Object {
"managed": true,
"managed_by": "observability",
"version": 3,
"version": 4,
},
"description": "Summarize every SLO with timeslices budgeting method and a 7 days rolling time window",
"dest": Object {
"index": ".slo-observability.summary-v2",
"index": ".slo-observability.summary-v3",
"pipeline": ".slo-observability.summary.pipeline",
},
"frequency": "1m",
@ -52,6 +52,11 @@ Array [
"field": "slo.isGoodSlice",
},
},
"latestSliTimestamp": Object {
"max": Object {
"field": "@timestamp",
},
},
"sliValue": Object {
"bucket_script": Object {
"buckets_path": Object {
@ -107,46 +112,21 @@ Array [
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
@ -176,7 +156,7 @@ Array [
"unattended": true,
},
"source": Object {
"index": ".slo-observability.sli-v2*",
"index": ".slo-observability.sli-v3*",
"query": Object {
"bool": Object {
"filter": Array [
@ -219,8 +199,8 @@ Array [
},
"sync": Object {
"time": Object {
"delay": "125s",
"field": "@timestamp",
"delay": "65s",
"field": "event.ingested",
},
},
"transform_id": "slo-summary-timeslices-7d-rolling",
@ -236,11 +216,11 @@ Array [
"_meta": Object {
"managed": true,
"managed_by": "observability",
"version": 3,
"version": 4,
},
"description": "Summarize every SLO with timeslices budgeting method and a 30 days rolling time window",
"dest": Object {
"index": ".slo-observability.summary-v2",
"index": ".slo-observability.summary-v3",
"pipeline": ".slo-observability.summary.pipeline",
},
"frequency": "1m",
@ -281,6 +261,11 @@ Array [
"field": "slo.isGoodSlice",
},
},
"latestSliTimestamp": Object {
"max": Object {
"field": "@timestamp",
},
},
"sliValue": Object {
"bucket_script": Object {
"buckets_path": Object {
@ -336,46 +321,21 @@ Array [
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
@ -405,7 +365,7 @@ Array [
"unattended": true,
},
"source": Object {
"index": ".slo-observability.sli-v2*",
"index": ".slo-observability.sli-v3*",
"query": Object {
"bool": Object {
"filter": Array [
@ -448,8 +408,8 @@ Array [
},
"sync": Object {
"time": Object {
"delay": "125s",
"field": "@timestamp",
"delay": "65s",
"field": "event.ingested",
},
},
"transform_id": "slo-summary-timeslices-30d-rolling",
@ -465,11 +425,11 @@ Array [
"_meta": Object {
"managed": true,
"managed_by": "observability",
"version": 3,
"version": 4,
},
"description": "Summarize every SLO with timeslices budgeting method and a 90 days rolling time window",
"dest": Object {
"index": ".slo-observability.summary-v2",
"index": ".slo-observability.summary-v3",
"pipeline": ".slo-observability.summary.pipeline",
},
"frequency": "1m",
@ -510,6 +470,11 @@ Array [
"field": "slo.isGoodSlice",
},
},
"latestSliTimestamp": Object {
"max": Object {
"field": "@timestamp",
},
},
"sliValue": Object {
"bucket_script": Object {
"buckets_path": Object {
@ -565,46 +530,21 @@ Array [
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
@ -634,7 +574,7 @@ Array [
"unattended": true,
},
"source": Object {
"index": ".slo-observability.sli-v2*",
"index": ".slo-observability.sli-v3*",
"query": Object {
"bool": Object {
"filter": Array [
@ -677,8 +617,8 @@ Array [
},
"sync": Object {
"time": Object {
"delay": "125s",
"field": "@timestamp",
"delay": "65s",
"field": "event.ingested",
},
},
"transform_id": "slo-summary-timeslices-90d-rolling",
@ -694,11 +634,11 @@ Array [
"_meta": Object {
"managed": true,
"managed_by": "observability",
"version": 3,
"version": 4,
},
"description": "Summarize every SLO with timeslices budgeting method and a weekly calendar aligned time window",
"dest": Object {
"index": ".slo-observability.summary-v2",
"index": ".slo-observability.summary-v3",
"pipeline": ".slo-observability.summary.pipeline",
},
"frequency": "1m",
@ -754,6 +694,11 @@ Array [
"field": "slo.isGoodSlice",
},
},
"latestSliTimestamp": Object {
"max": Object {
"field": "@timestamp",
},
},
"sliValue": Object {
"bucket_script": Object {
"buckets_path": Object {
@ -807,46 +752,21 @@ Array [
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
@ -876,7 +796,7 @@ Array [
"unattended": true,
},
"source": Object {
"index": ".slo-observability.sli-v2*",
"index": ".slo-observability.sli-v3*",
"query": Object {
"bool": Object {
"filter": Array [
@ -919,8 +839,8 @@ Array [
},
"sync": Object {
"time": Object {
"delay": "125s",
"field": "@timestamp",
"delay": "65s",
"field": "event.ingested",
},
},
"transform_id": "slo-summary-timeslices-weekly-aligned",
@ -936,11 +856,11 @@ Array [
"_meta": Object {
"managed": true,
"managed_by": "observability",
"version": 3,
"version": 4,
},
"description": "Summarize every SLO with timeslices budgeting method and a monthly calendar aligned time window",
"dest": Object {
"index": ".slo-observability.summary-v2",
"index": ".slo-observability.summary-v3",
"pipeline": ".slo-observability.summary.pipeline",
},
"frequency": "1m",
@ -963,7 +883,7 @@ Array [
},
"script": Object {
"source": "
Date d = new Date();
Date d = new Date();
Instant instant = Instant.ofEpochMilli(d.getTime());
LocalDateTime now = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
LocalDateTime startOfMonth = now
@ -973,7 +893,7 @@ Array [
.withSecond(0);
LocalDateTime startOfNextMonth = startOfMonth.plusMonths(1);
double sliceDurationInMinutes = params.sliceDurationInSeconds / 60;
return Math.ceil(Duration.between(startOfMonth, startOfNextMonth).toMinutes() / sliceDurationInMinutes);
",
},
@ -1011,6 +931,11 @@ Array [
"field": "slo.isGoodSlice",
},
},
"latestSliTimestamp": Object {
"max": Object {
"field": "@timestamp",
},
},
"sliValue": Object {
"bucket_script": Object {
"buckets_path": Object {
@ -1064,46 +989,21 @@ Array [
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
@ -1133,7 +1033,7 @@ Array [
"unattended": true,
},
"source": Object {
"index": ".slo-observability.sli-v2*",
"index": ".slo-observability.sli-v3*",
"query": Object {
"bool": Object {
"filter": Array [
@ -1176,8 +1076,8 @@ Array [
},
"sync": Object {
"time": Object {
"delay": "125s",
"field": "@timestamp",
"delay": "65s",
"field": "event.ingested",
},
},
"transform_id": "slo-summary-timeslices-monthly-aligned",

View file

@ -16,36 +16,11 @@ export const groupBy = {
field: 'slo.revision',
},
},
'slo.groupBy': {
terms: {
field: 'slo.groupBy',
},
},
'slo.instanceId': {
terms: {
field: 'slo.instanceId',
},
},
'slo.name': {
terms: {
field: 'slo.name',
},
},
'slo.description': {
terms: {
field: 'slo.description',
},
},
'slo.tags': {
terms: {
field: 'slo.tags',
},
},
'slo.indicator.type': {
terms: {
field: 'slo.indicator.type',
},
},
'slo.budgetingMethod': {
terms: {
field: 'slo.budgetingMethod',

View file

@ -130,6 +130,11 @@ export const SUMMARY_OCCURRENCES_30D_ROLLING: TransformPutTransformRequest = {
},
},
},
latestSliTimestamp: {
max: {
field: '@timestamp',
},
},
},
},
description:
@ -137,8 +142,8 @@ export const SUMMARY_OCCURRENCES_30D_ROLLING: TransformPutTransformRequest = {
frequency: '1m',
sync: {
time: {
field: '@timestamp',
delay: '125s',
field: 'event.ingested',
delay: '65s',
},
},
settings: {

View file

@ -130,6 +130,11 @@ export const SUMMARY_OCCURRENCES_7D_ROLLING: TransformPutTransformRequest = {
},
},
},
latestSliTimestamp: {
max: {
field: '@timestamp',
},
},
},
},
description:
@ -137,8 +142,8 @@ export const SUMMARY_OCCURRENCES_7D_ROLLING: TransformPutTransformRequest = {
frequency: '1m',
sync: {
time: {
field: '@timestamp',
delay: '125s',
field: 'event.ingested',
delay: '65s',
},
},
settings: {

View file

@ -130,6 +130,11 @@ export const SUMMARY_OCCURRENCES_90D_ROLLING: TransformPutTransformRequest = {
},
},
},
latestSliTimestamp: {
max: {
field: '@timestamp',
},
},
},
},
description:
@ -137,8 +142,8 @@ export const SUMMARY_OCCURRENCES_90D_ROLLING: TransformPutTransformRequest = {
frequency: '1m',
sync: {
time: {
field: '@timestamp',
delay: '125s',
field: 'event.ingested',
delay: '65s',
},
},
settings: {

View file

@ -128,6 +128,11 @@ export const SUMMARY_OCCURRENCES_MONTHLY_ALIGNED: TransformPutTransformRequest =
'if (params.sliValue == -1) { return 0 } else if (params.sliValue >= params.objective) { return 4 } else if (params.errorBudgetRemaining > 0) { return 2 } else { return 1 }',
},
},
latestSliTimestamp: {
max: {
field: '@timestamp',
},
},
},
},
description:
@ -135,8 +140,8 @@ export const SUMMARY_OCCURRENCES_MONTHLY_ALIGNED: TransformPutTransformRequest =
frequency: '1m',
sync: {
time: {
field: '@timestamp',
delay: '125s',
field: 'event.ingested',
delay: '65s',
},
},
settings: {

View file

@ -128,6 +128,11 @@ export const SUMMARY_OCCURRENCES_WEEKLY_ALIGNED: TransformPutTransformRequest =
'if (params.sliValue == -1) { return 0 } else if (params.sliValue >= params.objective) { return 4 } else if (params.errorBudgetRemaining > 0) { return 2 } else { return 1 }',
},
},
latestSliTimestamp: {
max: {
field: '@timestamp',
},
},
},
},
description:
@ -135,8 +140,8 @@ export const SUMMARY_OCCURRENCES_WEEKLY_ALIGNED: TransformPutTransformRequest =
frequency: '1m',
sync: {
time: {
field: '@timestamp',
delay: '125s',
field: 'event.ingested',
delay: '65s',
},
},
settings: {

View file

@ -130,6 +130,11 @@ export const SUMMARY_TIMESLICES_30D_ROLLING: TransformPutTransformRequest = {
},
},
},
latestSliTimestamp: {
max: {
field: '@timestamp',
},
},
},
},
description:
@ -137,8 +142,8 @@ export const SUMMARY_TIMESLICES_30D_ROLLING: TransformPutTransformRequest = {
frequency: '1m',
sync: {
time: {
field: '@timestamp',
delay: '125s',
field: 'event.ingested',
delay: '65s',
},
},
settings: {

View file

@ -130,6 +130,11 @@ export const SUMMARY_TIMESLICES_7D_ROLLING: TransformPutTransformRequest = {
},
},
},
latestSliTimestamp: {
max: {
field: '@timestamp',
},
},
},
},
description:
@ -137,8 +142,8 @@ export const SUMMARY_TIMESLICES_7D_ROLLING: TransformPutTransformRequest = {
frequency: '1m',
sync: {
time: {
field: '@timestamp',
delay: '125s',
field: 'event.ingested',
delay: '65s',
},
},
settings: {

View file

@ -130,6 +130,11 @@ export const SUMMARY_TIMESLICES_90D_ROLLING: TransformPutTransformRequest = {
},
},
},
latestSliTimestamp: {
max: {
field: '@timestamp',
},
},
},
},
description:
@ -137,8 +142,8 @@ export const SUMMARY_TIMESLICES_90D_ROLLING: TransformPutTransformRequest = {
frequency: '1m',
sync: {
time: {
field: '@timestamp',
delay: '125s',
field: 'event.ingested',
delay: '65s',
},
},
settings: {

View file

@ -78,7 +78,7 @@ export const SUMMARY_TIMESLICES_MONTHLY_ALIGNED: TransformPutTransformRequest =
},
script: {
source: `
Date d = new Date();
Date d = new Date();
Instant instant = Instant.ofEpochMilli(d.getTime());
LocalDateTime now = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
LocalDateTime startOfMonth = now
@ -88,7 +88,7 @@ export const SUMMARY_TIMESLICES_MONTHLY_ALIGNED: TransformPutTransformRequest =
.withSecond(0);
LocalDateTime startOfNextMonth = startOfMonth.plusMonths(1);
double sliceDurationInMinutes = params.sliceDurationInSeconds / 60;
return Math.ceil(Duration.between(startOfMonth, startOfNextMonth).toMinutes() / sliceDurationInMinutes);
`,
},
@ -158,6 +158,11 @@ export const SUMMARY_TIMESLICES_MONTHLY_ALIGNED: TransformPutTransformRequest =
'if (params.sliValue == -1) { return 0 } else if (params.sliValue >= params.objective) { return 4 } else if (params.errorBudgetRemaining > 0) { return 2 } else { return 1 }',
},
},
latestSliTimestamp: {
max: {
field: '@timestamp',
},
},
},
},
description:
@ -165,8 +170,8 @@ export const SUMMARY_TIMESLICES_MONTHLY_ALIGNED: TransformPutTransformRequest =
frequency: '1m',
sync: {
time: {
field: '@timestamp',
delay: '125s',
field: 'event.ingested',
delay: '65s',
},
},
settings: {

View file

@ -143,6 +143,11 @@ export const SUMMARY_TIMESLICES_WEEKLY_ALIGNED: TransformPutTransformRequest = {
'if (params.sliValue == -1) { return 0 } else if (params.sliValue >= params.objective) { return 4 } else if (params.errorBudgetRemaining > 0) { return 2 } else { return 1 }',
},
},
latestSliTimestamp: {
max: {
field: '@timestamp',
},
},
},
},
description:
@ -150,8 +155,8 @@ export const SUMMARY_TIMESLICES_WEEKLY_ALIGNED: TransformPutTransformRequest = {
frequency: '1m',
sync: {
time: {
field: '@timestamp',
delay: '125s',
field: 'event.ingested',
delay: '65s',
},
},
settings: {

View file

@ -190,66 +190,21 @@ Object {
"field": "service.environment",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
}
`;
@ -304,66 +259,21 @@ Object {
"field": "service.name",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
}
`;
@ -413,66 +323,21 @@ Object {
"fixed_interval": "1m",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
"transaction.name": Object {
"terms": Object {
"field": "transaction.name",
@ -527,66 +392,21 @@ Object {
"fixed_interval": "1m",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
"transaction.type": Object {
"terms": Object {
"field": "transaction.type",
@ -600,11 +420,11 @@ Object {
"_meta": Object {
"managed": true,
"managed_by": "observability",
"version": 2,
"version": 3,
},
"description": "Rolled-up SLI data for SLO: irrelevant",
"dest": Object {
"index": ".slo-observability.sli-v2",
"index": ".slo-observability.sli-v3",
"pipeline": ".slo-observability.sli.pipeline",
},
"frequency": "1m",
@ -660,71 +480,26 @@ Object {
"field": "service.name",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.sliceDurationInSeconds": Object {
"terms": Object {
"field": "slo.objective.sliceDurationInSeconds",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
"transaction.name": Object {
"terms": Object {
"field": "transaction.name",
@ -794,84 +569,30 @@ Object {
},
},
"runtime_mappings": Object {
"slo.budgetingMethod": Object {
"script": Object {
"source": "emit('timeslices')",
},
"type": "keyword",
},
"slo.description": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.groupBy": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.id": Object {
"script": Object {
"source": Any<String>,
},
"type": "keyword",
},
"slo.indicator.type": Object {
"script": Object {
"source": "emit('sli.apm.transactionDuration')",
},
"type": "keyword",
},
"slo.instanceId": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.name": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.objective.sliceDurationInSeconds": Object {
"script": Object {
"source": "emit(120)",
},
"type": "long",
},
"slo.objective.target": Object {
"script": Object {
"source": "emit(0.98)",
},
"type": "double",
},
"slo.revision": Object {
"script": Object {
"source": "emit(1)",
},
"type": "long",
},
"slo.tags": Object {
"script": Object {
"source": "emit('critical,k8s')",
},
"type": "keyword",
},
"slo.timeWindow.duration": Object {
"script": Object {
"source": "emit('7d')",
},
"type": "keyword",
},
"slo.timeWindow.type": Object {
"script": Object {
"source": "emit('rolling')",
},
"type": "keyword",
},
},
},
"sync": Object {
@ -889,11 +610,11 @@ Object {
"_meta": Object {
"managed": true,
"managed_by": "observability",
"version": 2,
"version": 3,
},
"description": "Rolled-up SLI data for SLO: irrelevant",
"dest": Object {
"index": ".slo-observability.sli-v2",
"index": ".slo-observability.sli-v3",
"pipeline": ".slo-observability.sli.pipeline",
},
"frequency": "1m",
@ -940,66 +661,21 @@ Object {
"field": "service.name",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
"transaction.name": Object {
"terms": Object {
"field": "transaction.name",
@ -1069,78 +745,24 @@ Object {
},
},
"runtime_mappings": Object {
"slo.budgetingMethod": Object {
"script": Object {
"source": "emit('occurrences')",
},
"type": "keyword",
},
"slo.description": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.groupBy": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.id": Object {
"script": Object {
"source": Any<String>,
},
"type": "keyword",
},
"slo.indicator.type": Object {
"script": Object {
"source": "emit('sli.apm.transactionDuration')",
},
"type": "keyword",
},
"slo.instanceId": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.name": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.objective.target": Object {
"script": Object {
"source": "emit(0.999)",
},
"type": "double",
},
"slo.revision": Object {
"script": Object {
"source": "emit(1)",
},
"type": "long",
},
"slo.tags": Object {
"script": Object {
"source": "emit('critical,k8s')",
},
"type": "keyword",
},
"slo.timeWindow.duration": Object {
"script": Object {
"source": "emit('7d')",
},
"type": "keyword",
},
"slo.timeWindow.type": Object {
"script": Object {
"source": "emit('rolling')",
},
"type": "keyword",
},
},
},
"sync": Object {

View file

@ -178,66 +178,21 @@ Object {
"field": "service.environment",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
}
`;
@ -288,66 +243,21 @@ Object {
"field": "service.name",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
}
`;
@ -393,66 +303,21 @@ Object {
"fixed_interval": "1m",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
"transaction.name": Object {
"terms": Object {
"field": "transaction.name",
@ -503,66 +368,21 @@ Object {
"fixed_interval": "1m",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
"transaction.type": Object {
"terms": Object {
"field": "transaction.type",
@ -576,11 +396,11 @@ Object {
"_meta": Object {
"managed": true,
"managed_by": "observability",
"version": 2,
"version": 3,
},
"description": "Rolled-up SLI data for SLO: irrelevant",
"dest": Object {
"index": ".slo-observability.sli-v2",
"index": ".slo-observability.sli-v3",
"pipeline": ".slo-observability.sli.pipeline",
},
"frequency": "1m",
@ -629,71 +449,26 @@ Object {
"field": "service.name",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.sliceDurationInSeconds": Object {
"terms": Object {
"field": "slo.objective.sliceDurationInSeconds",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
"transaction.name": Object {
"terms": Object {
"field": "transaction.name",
@ -759,84 +534,30 @@ Object {
},
},
"runtime_mappings": Object {
"slo.budgetingMethod": Object {
"script": Object {
"source": "emit('timeslices')",
},
"type": "keyword",
},
"slo.description": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.groupBy": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.id": Object {
"script": Object {
"source": Any<String>,
},
"type": "keyword",
},
"slo.indicator.type": Object {
"script": Object {
"source": "emit('sli.apm.transactionErrorRate')",
},
"type": "keyword",
},
"slo.instanceId": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.name": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.objective.sliceDurationInSeconds": Object {
"script": Object {
"source": "emit(120)",
},
"type": "long",
},
"slo.objective.target": Object {
"script": Object {
"source": "emit(0.98)",
},
"type": "double",
},
"slo.revision": Object {
"script": Object {
"source": "emit(1)",
},
"type": "long",
},
"slo.tags": Object {
"script": Object {
"source": "emit('critical,k8s')",
},
"type": "keyword",
},
"slo.timeWindow.duration": Object {
"script": Object {
"source": "emit('7d')",
},
"type": "keyword",
},
"slo.timeWindow.type": Object {
"script": Object {
"source": "emit('rolling')",
},
"type": "keyword",
},
},
},
"sync": Object {
@ -854,11 +575,11 @@ Object {
"_meta": Object {
"managed": true,
"managed_by": "observability",
"version": 2,
"version": 3,
},
"description": "Rolled-up SLI data for SLO: irrelevant",
"dest": Object {
"index": ".slo-observability.sli-v2",
"index": ".slo-observability.sli-v3",
"pipeline": ".slo-observability.sli.pipeline",
},
"frequency": "1m",
@ -898,66 +619,21 @@ Object {
"field": "service.name",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
"transaction.name": Object {
"terms": Object {
"field": "transaction.name",
@ -1023,78 +699,24 @@ Object {
},
},
"runtime_mappings": Object {
"slo.budgetingMethod": Object {
"script": Object {
"source": "emit('occurrences')",
},
"type": "keyword",
},
"slo.description": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.groupBy": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.id": Object {
"script": Object {
"source": Any<String>,
},
"type": "keyword",
},
"slo.indicator.type": Object {
"script": Object {
"source": "emit('sli.apm.transactionErrorRate')",
},
"type": "keyword",
},
"slo.instanceId": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.name": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.objective.target": Object {
"script": Object {
"source": "emit(0.999)",
},
"type": "double",
},
"slo.revision": Object {
"script": Object {
"source": "emit(1)",
},
"type": "long",
},
"slo.tags": Object {
"script": Object {
"source": "emit('critical,k8s')",
},
"type": "keyword",
},
"slo.timeWindow.duration": Object {
"script": Object {
"source": "emit('7d')",
},
"type": "keyword",
},
"slo.timeWindow.type": Object {
"script": Object {
"source": "emit('rolling')",
},
"type": "keyword",
},
},
},
"sync": Object {

View file

@ -77,11 +77,11 @@ Object {
"_meta": Object {
"managed": true,
"managed_by": "observability",
"version": 2,
"version": 3,
},
"description": "Rolled-up SLI data for SLO: irrelevant",
"dest": Object {
"index": ".slo-observability.sli-v2",
"index": ".slo-observability.sli-v3",
"pipeline": ".slo-observability.sli.pipeline",
},
"frequency": "1m",
@ -151,71 +151,26 @@ Object {
"fixed_interval": "2m",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.sliceDurationInSeconds": Object {
"terms": Object {
"field": "slo.objective.sliceDurationInSeconds",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
},
},
"settings": Object {
@ -253,84 +208,30 @@ Object {
},
},
"runtime_mappings": Object {
"slo.budgetingMethod": Object {
"script": Object {
"source": "emit('timeslices')",
},
"type": "keyword",
},
"slo.description": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.groupBy": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.id": Object {
"script": Object {
"source": Any<String>,
},
"type": "keyword",
},
"slo.indicator.type": Object {
"script": Object {
"source": "emit('sli.histogram.custom')",
},
"type": "keyword",
},
"slo.instanceId": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.name": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.objective.sliceDurationInSeconds": Object {
"script": Object {
"source": "emit(120)",
},
"type": "long",
},
"slo.objective.target": Object {
"script": Object {
"source": "emit(0.98)",
},
"type": "double",
},
"slo.revision": Object {
"script": Object {
"source": "emit(1)",
},
"type": "long",
},
"slo.tags": Object {
"script": Object {
"source": "emit('critical,k8s')",
},
"type": "keyword",
},
"slo.timeWindow.duration": Object {
"script": Object {
"source": "emit('7d')",
},
"type": "keyword",
},
"slo.timeWindow.type": Object {
"script": Object {
"source": "emit('rolling')",
},
"type": "keyword",
},
},
},
"sync": Object {
@ -348,11 +249,11 @@ Object {
"_meta": Object {
"managed": true,
"managed_by": "observability",
"version": 2,
"version": 3,
},
"description": "Rolled-up SLI data for SLO: irrelevant",
"dest": Object {
"index": ".slo-observability.sli-v2",
"index": ".slo-observability.sli-v3",
"pipeline": ".slo-observability.sli.pipeline",
},
"frequency": "1m",
@ -413,66 +314,21 @@ Object {
"fixed_interval": "1m",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
},
},
"settings": Object {
@ -510,78 +366,24 @@ Object {
},
},
"runtime_mappings": Object {
"slo.budgetingMethod": Object {
"script": Object {
"source": "emit('occurrences')",
},
"type": "keyword",
},
"slo.description": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.groupBy": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.id": Object {
"script": Object {
"source": Any<String>,
},
"type": "keyword",
},
"slo.indicator.type": Object {
"script": Object {
"source": "emit('sli.histogram.custom')",
},
"type": "keyword",
},
"slo.instanceId": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.name": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.objective.target": Object {
"script": Object {
"source": "emit(0.999)",
},
"type": "double",
},
"slo.revision": Object {
"script": Object {
"source": "emit(1)",
},
"type": "long",
},
"slo.tags": Object {
"script": Object {
"source": "emit('critical,k8s')",
},
"type": "keyword",
},
"slo.timeWindow.duration": Object {
"script": Object {
"source": "emit('7d')",
},
"type": "keyword",
},
"slo.timeWindow.type": Object {
"script": Object {
"source": "emit('rolling')",
},
"type": "keyword",
},
},
},
"sync": Object {

View file

@ -118,11 +118,11 @@ Object {
"_meta": Object {
"managed": true,
"managed_by": "observability",
"version": 2,
"version": 3,
},
"description": "Rolled-up SLI data for SLO: irrelevant",
"dest": Object {
"index": ".slo-observability.sli-v2",
"index": ".slo-observability.sli-v3",
"pipeline": ".slo-observability.sli.pipeline",
},
"frequency": "1m",
@ -166,71 +166,26 @@ Object {
"fixed_interval": "2m",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.sliceDurationInSeconds": Object {
"terms": Object {
"field": "slo.objective.sliceDurationInSeconds",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
},
},
"settings": Object {
@ -268,84 +223,30 @@ Object {
},
},
"runtime_mappings": Object {
"slo.budgetingMethod": Object {
"script": Object {
"source": "emit('timeslices')",
},
"type": "keyword",
},
"slo.description": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.groupBy": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.id": Object {
"script": Object {
"source": Any<String>,
},
"type": "keyword",
},
"slo.indicator.type": Object {
"script": Object {
"source": "emit('sli.kql.custom')",
},
"type": "keyword",
},
"slo.instanceId": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.name": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.objective.sliceDurationInSeconds": Object {
"script": Object {
"source": "emit(120)",
},
"type": "long",
},
"slo.objective.target": Object {
"script": Object {
"source": "emit(0.98)",
},
"type": "double",
},
"slo.revision": Object {
"script": Object {
"source": "emit(1)",
},
"type": "long",
},
"slo.tags": Object {
"script": Object {
"source": "emit('critical,k8s')",
},
"type": "keyword",
},
"slo.timeWindow.duration": Object {
"script": Object {
"source": "emit('7d')",
},
"type": "keyword",
},
"slo.timeWindow.type": Object {
"script": Object {
"source": "emit('rolling')",
},
"type": "keyword",
},
},
},
"sync": Object {
@ -363,11 +264,11 @@ Object {
"_meta": Object {
"managed": true,
"managed_by": "observability",
"version": 2,
"version": 3,
},
"description": "Rolled-up SLI data for SLO: irrelevant",
"dest": Object {
"index": ".slo-observability.sli-v2",
"index": ".slo-observability.sli-v3",
"pipeline": ".slo-observability.sli.pipeline",
},
"frequency": "1m",
@ -402,66 +303,21 @@ Object {
"fixed_interval": "1m",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
},
},
"settings": Object {
@ -499,78 +355,24 @@ Object {
},
},
"runtime_mappings": Object {
"slo.budgetingMethod": Object {
"script": Object {
"source": "emit('occurrences')",
},
"type": "keyword",
},
"slo.description": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.groupBy": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.id": Object {
"script": Object {
"source": Any<String>,
},
"type": "keyword",
},
"slo.indicator.type": Object {
"script": Object {
"source": "emit('sli.kql.custom')",
},
"type": "keyword",
},
"slo.instanceId": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.name": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.objective.target": Object {
"script": Object {
"source": "emit(0.999)",
},
"type": "double",
},
"slo.revision": Object {
"script": Object {
"source": "emit(1)",
},
"type": "long",
},
"slo.tags": Object {
"script": Object {
"source": "emit('critical,k8s')",
},
"type": "keyword",
},
"slo.timeWindow.duration": Object {
"script": Object {
"source": "emit('7d')",
},
"type": "keyword",
},
"slo.timeWindow.type": Object {
"script": Object {
"source": "emit('rolling')",
},
"type": "keyword",
},
},
},
"sync": Object {

View file

@ -117,11 +117,11 @@ Object {
"_meta": Object {
"managed": true,
"managed_by": "observability",
"version": 2,
"version": 3,
},
"description": "Rolled-up SLI data for SLO: irrelevant",
"dest": Object {
"index": ".slo-observability.sli-v2",
"index": ".slo-observability.sli-v3",
"pipeline": ".slo-observability.sli.pipeline",
},
"frequency": "1m",
@ -203,71 +203,26 @@ Object {
"fixed_interval": "2m",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.sliceDurationInSeconds": Object {
"terms": Object {
"field": "slo.objective.sliceDurationInSeconds",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
},
},
"settings": Object {
@ -305,84 +260,30 @@ Object {
},
},
"runtime_mappings": Object {
"slo.budgetingMethod": Object {
"script": Object {
"source": "emit('timeslices')",
},
"type": "keyword",
},
"slo.description": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.groupBy": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.id": Object {
"script": Object {
"source": Any<String>,
},
"type": "keyword",
},
"slo.indicator.type": Object {
"script": Object {
"source": "emit('sli.metric.custom')",
},
"type": "keyword",
},
"slo.instanceId": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.name": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.objective.sliceDurationInSeconds": Object {
"script": Object {
"source": "emit(120)",
},
"type": "long",
},
"slo.objective.target": Object {
"script": Object {
"source": "emit(0.98)",
},
"type": "double",
},
"slo.revision": Object {
"script": Object {
"source": "emit(1)",
},
"type": "long",
},
"slo.tags": Object {
"script": Object {
"source": "emit('critical,k8s')",
},
"type": "keyword",
},
"slo.timeWindow.duration": Object {
"script": Object {
"source": "emit('7d')",
},
"type": "keyword",
},
"slo.timeWindow.type": Object {
"script": Object {
"source": "emit('rolling')",
},
"type": "keyword",
},
},
},
"sync": Object {
@ -400,11 +301,11 @@ Object {
"_meta": Object {
"managed": true,
"managed_by": "observability",
"version": 2,
"version": 3,
},
"description": "Rolled-up SLI data for SLO: irrelevant",
"dest": Object {
"index": ".slo-observability.sli-v2",
"index": ".slo-observability.sli-v3",
"pipeline": ".slo-observability.sli.pipeline",
},
"frequency": "1m",
@ -477,66 +378,21 @@ Object {
"fixed_interval": "1m",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
},
},
"settings": Object {
@ -574,78 +430,24 @@ Object {
},
},
"runtime_mappings": Object {
"slo.budgetingMethod": Object {
"script": Object {
"source": "emit('occurrences')",
},
"type": "keyword",
},
"slo.description": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.groupBy": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.id": Object {
"script": Object {
"source": Any<String>,
},
"type": "keyword",
},
"slo.indicator.type": Object {
"script": Object {
"source": "emit('sli.metric.custom')",
},
"type": "keyword",
},
"slo.instanceId": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.name": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.objective.target": Object {
"script": Object {
"source": "emit(0.999)",
},
"type": "double",
},
"slo.revision": Object {
"script": Object {
"source": "emit(1)",
},
"type": "long",
},
"slo.tags": Object {
"script": Object {
"source": "emit('critical,k8s')",
},
"type": "keyword",
},
"slo.timeWindow.duration": Object {
"script": Object {
"source": "emit('7d')",
},
"type": "keyword",
},
"slo.timeWindow.type": Object {
"script": Object {
"source": "emit('rolling')",
},
"type": "keyword",
},
},
},
"sync": Object {

View file

@ -33,11 +33,11 @@ Object {
"_meta": Object {
"managed": true,
"managed_by": "observability",
"version": 2,
"version": 3,
},
"description": "Rolled-up SLI data for SLO: irrelevant",
"dest": Object {
"index": ".slo-observability.sli-v2",
"index": ".slo-observability.sli-v3",
"pipeline": ".slo-observability.sli.pipeline",
},
"frequency": "1m",
@ -173,71 +173,26 @@ Object {
"fixed_interval": "2m",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.sliceDurationInSeconds": Object {
"terms": Object {
"field": "slo.objective.sliceDurationInSeconds",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
},
},
"settings": Object {
@ -272,84 +227,30 @@ Object {
},
},
"runtime_mappings": Object {
"slo.budgetingMethod": Object {
"script": Object {
"source": "emit('timeslices')",
},
"type": "keyword",
},
"slo.description": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.groupBy": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.id": Object {
"script": Object {
"source": Any<String>,
},
"type": "keyword",
},
"slo.indicator.type": Object {
"script": Object {
"source": "emit('sli.metric.timeslice')",
},
"type": "keyword",
},
"slo.instanceId": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.name": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.objective.sliceDurationInSeconds": Object {
"script": Object {
"source": "emit(120)",
},
"type": "long",
},
"slo.objective.target": Object {
"script": Object {
"source": "emit(0.98)",
},
"type": "double",
},
"slo.revision": Object {
"script": Object {
"source": "emit(1)",
},
"type": "long",
},
"slo.tags": Object {
"script": Object {
"source": "emit('critical,k8s')",
},
"type": "keyword",
},
"slo.timeWindow.duration": Object {
"script": Object {
"source": "emit('7d')",
},
"type": "keyword",
},
"slo.timeWindow.type": Object {
"script": Object {
"source": "emit('rolling')",
},
"type": "keyword",
},
},
},
"sync": Object {
@ -367,11 +268,11 @@ Object {
"_meta": Object {
"managed": true,
"managed_by": "observability",
"version": 2,
"version": 3,
},
"description": "Rolled-up SLI data for SLO: irrelevant",
"dest": Object {
"index": ".slo-observability.sli-v2",
"index": ".slo-observability.sli-v3",
"pipeline": ".slo-observability.sli.pipeline",
},
"frequency": "1m",
@ -507,71 +408,26 @@ Object {
"fixed_interval": "2m",
},
},
"slo.budgetingMethod": Object {
"terms": Object {
"field": "slo.budgetingMethod",
},
},
"slo.description": Object {
"terms": Object {
"field": "slo.description",
},
},
"slo.groupBy": Object {
"terms": Object {
"field": "slo.groupBy",
},
},
"slo.id": Object {
"terms": Object {
"field": "slo.id",
},
},
"slo.indicator.type": Object {
"terms": Object {
"field": "slo.indicator.type",
},
},
"slo.instanceId": Object {
"terms": Object {
"field": "slo.instanceId",
},
},
"slo.name": Object {
"terms": Object {
"field": "slo.name",
},
},
"slo.objective.sliceDurationInSeconds": Object {
"terms": Object {
"field": "slo.objective.sliceDurationInSeconds",
},
},
"slo.objective.target": Object {
"terms": Object {
"field": "slo.objective.target",
},
},
"slo.revision": Object {
"terms": Object {
"field": "slo.revision",
},
},
"slo.tags": Object {
"terms": Object {
"field": "slo.tags",
},
},
"slo.timeWindow.duration": Object {
"terms": Object {
"field": "slo.timeWindow.duration",
},
},
"slo.timeWindow.type": Object {
"terms": Object {
"field": "slo.timeWindow.type",
},
},
},
},
"settings": Object {
@ -606,84 +462,30 @@ Object {
},
},
"runtime_mappings": Object {
"slo.budgetingMethod": Object {
"script": Object {
"source": "emit('timeslices')",
},
"type": "keyword",
},
"slo.description": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.groupBy": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.id": Object {
"script": Object {
"source": Any<String>,
},
"type": "keyword",
},
"slo.indicator.type": Object {
"script": Object {
"source": "emit('sli.metric.timeslice')",
},
"type": "keyword",
},
"slo.instanceId": Object {
"script": Object {
"source": "emit('*')",
},
"type": "keyword",
},
"slo.name": Object {
"script": Object {
"source": "emit('irrelevant')",
},
"type": "keyword",
},
"slo.objective.sliceDurationInSeconds": Object {
"script": Object {
"source": "emit(120)",
},
"type": "long",
},
"slo.objective.target": Object {
"script": Object {
"source": "emit(0.98)",
},
"type": "double",
},
"slo.revision": Object {
"script": Object {
"source": "emit(1)",
},
"type": "long",
},
"slo.tags": Object {
"script": Object {
"source": "emit('critical,k8s')",
},
"type": "keyword",
},
"slo.timeWindow.duration": Object {
"script": Object {
"source": "emit('7d')",
},
"type": "keyword",
},
"slo.timeWindow.type": Object {
"script": Object {
"source": "emit('rolling')",
},
"type": "keyword",
},
},
},
"sync": Object {

View file

@ -32,12 +32,6 @@ export abstract class TransformGenerator {
source: `emit(${slo.revision})`,
},
},
'slo.groupBy': {
type: 'keyword',
script: {
source: `emit('${!!slo.groupBy ? slo.groupBy : ALL_VALUE}')`,
},
},
...(mustIncludeAllInstanceId && {
'slo.instanceId': {
type: 'keyword',
@ -46,36 +40,6 @@ export abstract class TransformGenerator {
},
},
}),
'slo.name': {
type: 'keyword',
script: {
source: `emit('${slo.name}')`,
},
},
'slo.description': {
type: 'keyword',
script: {
source: `emit('${slo.description}')`,
},
},
'slo.tags': {
type: 'keyword',
script: {
source: `emit('${slo.tags}')`,
},
},
'slo.indicator.type': {
type: 'keyword',
script: {
source: `emit('${slo.indicator.type}')`,
},
},
'slo.objective.target': {
type: 'double',
script: {
source: `emit(${slo.objective.target})`,
},
},
...(slo.objective.timesliceWindow && {
'slo.objective.sliceDurationInSeconds': {
type: 'long',
@ -84,24 +48,6 @@ export abstract class TransformGenerator {
},
},
}),
'slo.budgetingMethod': {
type: 'keyword',
script: {
source: `emit('${slo.budgetingMethod}')`,
},
},
'slo.timeWindow.duration': {
type: 'keyword',
script: {
source: `emit('${slo.timeWindow.duration.format()}')`,
},
},
'slo.timeWindow.type': {
type: 'keyword',
script: {
source: `emit('${slo.timeWindow.type}')`,
},
},
};
}
@ -125,21 +71,12 @@ export abstract class TransformGenerator {
return {
'slo.id': { terms: { field: 'slo.id' } },
'slo.revision': { terms: { field: 'slo.revision' } },
'slo.groupBy': { terms: { field: 'slo.groupBy' } },
'slo.instanceId': { terms: { field: instanceIdField } },
'slo.name': { terms: { field: 'slo.name' } },
'slo.description': { terms: { field: 'slo.description' } },
'slo.tags': { terms: { field: 'slo.tags' } },
'slo.indicator.type': { terms: { field: 'slo.indicator.type' } },
'slo.objective.target': { terms: { field: 'slo.objective.target' } },
...(slo.objective.timesliceWindow && {
'slo.objective.sliceDurationInSeconds': {
terms: { field: 'slo.objective.sliceDurationInSeconds' },
},
}),
'slo.budgetingMethod': { terms: { field: 'slo.budgetingMethod' } },
'slo.timeWindow.duration': { terms: { field: 'slo.timeWindow.duration' } },
'slo.timeWindow.type': { terms: { field: 'slo.timeWindow.type' } },
...extraGroupByFields,
// @timestamp field defined in the destination index
'@timestamp': {

View file

@ -8,7 +8,7 @@
import { ElasticsearchClient } from '@kbn/core/server';
import { elasticsearchServiceMock } from '@kbn/core/server/mocks';
import { UpdateSLOParams } from '@kbn/slo-schema';
import { cloneDeep, pick, omit } from 'lodash';
import { cloneDeep, omit, pick } from 'lodash';
import {
getSLOTransformId,
@ -16,12 +16,14 @@ import {
SLO_SUMMARY_DESTINATION_INDEX_PATTERN,
} from '../../assets/constants';
import { SLO } from '../../domain/models';
import { fiveMinute, oneMinute } from './fixtures/duration';
import { fiveMinute, oneMinute, twoMinute } from './fixtures/duration';
import {
createAPMTransactionErrorRateIndicator,
createSLO,
createSLOWithTimeslicesBudgetingMethod,
createMetricCustomIndicator,
} from './fixtures/slo';
import { thirtyDaysRolling } from './fixtures/time_window';
import { createSLORepositoryMock, createTransformManagerMock } from './mocks';
import { SLORepository } from './slo_repository';
import { TransformManager } from './transform_manager';
@ -31,25 +33,23 @@ describe('UpdateSLO', () => {
let mockRepository: jest.Mocked<SLORepository>;
let mockTransformManager: jest.Mocked<TransformManager>;
let mockEsClient: jest.Mocked<ElasticsearchClient>;
let mockSystemEsClient: jest.Mocked<ElasticsearchClient>;
let updateSLO: UpdateSLO;
beforeEach(() => {
mockRepository = createSLORepositoryMock();
mockTransformManager = createTransformManagerMock();
mockEsClient = elasticsearchServiceMock.createElasticsearchClient();
updateSLO = new UpdateSLO(mockRepository, mockTransformManager, mockEsClient);
mockSystemEsClient = elasticsearchServiceMock.createElasticsearchClient();
updateSLO = new UpdateSLO(
mockRepository,
mockTransformManager,
mockEsClient,
mockSystemEsClient
);
});
describe('when the update payload does not change the original SLO', () => {
function expectNoCallsToAnyMocks() {
expect(mockTransformManager.stop).not.toBeCalled();
expect(mockTransformManager.uninstall).not.toBeCalled();
expect(mockTransformManager.install).not.toBeCalled();
expect(mockTransformManager.preview).not.toBeCalled();
expect(mockTransformManager.start).not.toBeCalled();
expect(mockEsClient.deleteByQuery).not.toBeCalled();
}
it('returns early with a full identical SLO payload', async () => {
const slo = createSLO();
mockRepository.findById.mockResolvedValueOnce(slo);
@ -157,11 +157,14 @@ describe('UpdateSLO', () => {
});
});
it('updates the settings correctly', async () => {
it("bumps the revision when changing 'settings'", async () => {
const slo = createSLO();
mockRepository.findById.mockResolvedValueOnce(slo);
const newSettings = {
syncDelay: twoMinute(),
frequency: fiveMinute(),
};
const newSettings = { ...slo.settings, timestamp_field: 'newField' };
await updateSLO.execute(slo.id, { settings: newSettings });
expectDeletionOfOriginalSLO(slo);
@ -169,14 +172,14 @@ describe('UpdateSLO', () => {
expect.objectContaining({
...slo,
settings: newSettings,
revision: 2,
revision: slo.revision + 1,
updatedAt: expect.anything(),
})
);
expectInstallationOfNewSLOTransform();
});
it('updates the budgeting method correctly', async () => {
it("bumps the revision when changing 'budgetingMethod'", async () => {
const slo = createSLO({ budgetingMethod: 'occurrences' });
mockRepository.findById.mockResolvedValueOnce(slo);
@ -190,10 +193,23 @@ describe('UpdateSLO', () => {
});
expectDeletionOfOriginalSLO(slo);
expect(mockRepository.save).toBeCalledWith(
expect.objectContaining({
...slo,
budgetingMethod: 'timeslices',
objective: {
target: slo.objective.target,
timesliceTarget: 0.9,
timesliceWindow: oneMinute(),
},
revision: slo.revision + 1,
updatedAt: expect.anything(),
})
);
expectInstallationOfNewSLOTransform();
});
it('updates the timeslice target correctly', async () => {
it("bumps the revision when changing 'objective.timesliceTarget'", async () => {
const slo = createSLOWithTimeslicesBudgetingMethod();
mockRepository.findById.mockResolvedValueOnce(slo);
@ -206,10 +222,22 @@ describe('UpdateSLO', () => {
});
expectDeletionOfOriginalSLO(slo);
expect(mockRepository.save).toBeCalledWith(
expect.objectContaining({
...slo,
objective: {
target: slo.objective.target,
timesliceTarget: 0.1,
timesliceWindow: slo.objective.timesliceWindow,
},
revision: slo.revision + 1,
updatedAt: expect.anything(),
})
);
expectInstallationOfNewSLOTransform();
});
it('consideres a timeslice window change as a breaking change', async () => {
it("bumps the revision when changing 'objective.timesliceWindow'", async () => {
const slo = createSLOWithTimeslicesBudgetingMethod();
mockRepository.findById.mockResolvedValueOnce(slo);
@ -222,41 +250,165 @@ describe('UpdateSLO', () => {
});
expectDeletionOfOriginalSLO(slo);
expectInstallationOfNewSLOTransform();
});
it('index a temporary summary document', async () => {
const slo = createSLO({
id: 'unique-id',
indicator: createAPMTransactionErrorRateIndicator({ environment: 'development' }),
});
mockRepository.findById.mockResolvedValueOnce(slo);
const newIndicator = createAPMTransactionErrorRateIndicator({ environment: 'production' });
await updateSLO.execute(slo.id, { indicator: newIndicator });
expect(mockEsClient.index.mock.calls[0]).toMatchSnapshot();
});
it('removes the original data from the original SLO', async () => {
const slo = createSLO({
indicator: createAPMTransactionErrorRateIndicator({ environment: 'development' }),
});
mockRepository.findById.mockResolvedValueOnce(slo);
const newIndicator = createAPMTransactionErrorRateIndicator({ environment: 'production' });
await updateSLO.execute(slo.id, { indicator: newIndicator });
expect(mockRepository.save).toBeCalledWith(
expect.objectContaining({
...slo,
indicator: newIndicator,
revision: 2,
objective: {
target: slo.objective.target,
timesliceTarget: slo.objective.timesliceTarget,
timesliceWindow: fiveMinute(),
},
revision: slo.revision + 1,
updatedAt: expect.anything(),
})
);
expectInstallationOfNewSLOTransform();
});
it("bumps the revision when changing 'objective'", async () => {
const slo = createSLO();
mockRepository.findById.mockResolvedValueOnce(slo);
await updateSLO.execute(slo.id, {
objective: {
target: 0.5,
},
});
expectDeletionOfOriginalSLO(slo);
expect(mockRepository.save).toBeCalledWith(
expect.objectContaining({
...slo,
objective: {
target: 0.5,
},
revision: slo.revision + 1,
updatedAt: expect.anything(),
})
);
expectInstallationOfNewSLOTransform();
});
it("bumps the revision when changing 'timeWindow'", async () => {
const slo = createSLO();
mockRepository.findById.mockResolvedValueOnce(slo);
await updateSLO.execute(slo.id, {
timeWindow: thirtyDaysRolling(),
});
expectDeletionOfOriginalSLO(slo);
expect(mockRepository.save).toBeCalledWith(
expect.objectContaining({
...slo,
timeWindow: thirtyDaysRolling(),
revision: slo.revision + 1,
updatedAt: expect.anything(),
})
);
expectInstallationOfNewSLOTransform();
});
it("bumps the revision when changing 'groupBy'", async () => {
const slo = createSLO({ groupBy: 'labels.projectId' });
mockRepository.findById.mockResolvedValueOnce(slo);
await updateSLO.execute(slo.id, {
groupBy: '*',
});
expectDeletionOfOriginalSLO(slo);
expect(mockRepository.save).toBeCalledWith(
expect.objectContaining({
...slo,
groupBy: '*',
revision: slo.revision + 1,
updatedAt: expect.anything(),
})
);
expectInstallationOfNewSLOTransform();
});
it("bumps the revision when changing 'indicator'", async () => {
const slo = createSLO();
mockRepository.findById.mockResolvedValueOnce(slo);
await updateSLO.execute(slo.id, {
indicator: createMetricCustomIndicator(),
});
expectDeletionOfOriginalSLO(slo);
expect(mockRepository.save).toBeCalledWith(
expect.objectContaining({
...slo,
indicator: createMetricCustomIndicator(),
revision: slo.revision + 1,
updatedAt: expect.anything(),
})
);
expectInstallationOfNewSLOTransform();
});
describe('when the revision does not bump', () => {
it('stores the updated SLO', async () => {
const slo = createSLO();
mockRepository.findById.mockResolvedValueOnce(slo);
await updateSLO.execute(slo.id, {
name: 'a new name',
description: 'a new description',
tags: ['some', 'new tags'],
});
expect(mockRepository.save).toBeCalledWith(
expect.objectContaining({
...slo,
name: 'a new name',
description: 'a new description',
tags: ['some', 'new tags'],
revision: slo.revision,
updatedAt: expect.anything(),
})
);
expectNoCallsToAnyMocks();
});
});
describe('when the revision bumps', () => {
it('indexes a temporary summary document', async () => {
const slo = createSLO({
id: 'unique-id',
indicator: createAPMTransactionErrorRateIndicator({ environment: 'development' }),
});
mockRepository.findById.mockResolvedValueOnce(slo);
const newIndicator = createAPMTransactionErrorRateIndicator({ environment: 'production' });
await updateSLO.execute(slo.id, { indicator: newIndicator });
expect(mockEsClient.index.mock.calls[0]).toMatchSnapshot();
expect(mockSystemEsClient.enrich.executePolicy).toBeCalled();
});
it('removes the original data from the original SLO', async () => {
const slo = createSLO({
indicator: createAPMTransactionErrorRateIndicator({ environment: 'development' }),
});
mockRepository.findById.mockResolvedValueOnce(slo);
const newIndicator = createAPMTransactionErrorRateIndicator({ environment: 'production' });
await updateSLO.execute(slo.id, { indicator: newIndicator });
expect(mockRepository.save).toBeCalledWith(
expect.objectContaining({
...slo,
indicator: newIndicator,
revision: 2,
updatedAt: expect.anything(),
})
);
expectInstallationOfNewSLOTransform();
expectDeletionOfOriginalSLO(slo);
});
});
describe('when error happens during the transform installation step', () => {
@ -274,6 +426,7 @@ describe('UpdateSLO', () => {
);
expect(mockRepository.save).toHaveBeenCalledWith(slo);
expect(mockSystemEsClient.enrich.executePolicy).toHaveBeenCalled();
expect(mockTransformManager.preview).not.toHaveBeenCalled();
expect(mockTransformManager.start).not.toHaveBeenCalled();
expect(mockTransformManager.stop).not.toHaveBeenCalled();
@ -300,11 +453,21 @@ describe('UpdateSLO', () => {
getSLOTransformId(slo.id, slo.revision + 1)
);
expect(mockRepository.save).toHaveBeenCalledWith(slo);
expect(mockSystemEsClient.enrich.executePolicy).toHaveBeenCalled();
expect(mockTransformManager.stop).not.toHaveBeenCalled();
expect(mockEsClient.deleteByQuery).not.toHaveBeenCalled();
});
});
function expectNoCallsToAnyMocks() {
expect(mockTransformManager.stop).not.toBeCalled();
expect(mockTransformManager.uninstall).not.toBeCalled();
expect(mockTransformManager.install).not.toBeCalled();
expect(mockTransformManager.preview).not.toBeCalled();
expect(mockTransformManager.start).not.toBeCalled();
expect(mockEsClient.deleteByQuery).not.toBeCalled();
}
function expectInstallationOfNewSLOTransform() {
expect(mockTransformManager.install).toBeCalled();
expect(mockTransformManager.preview).toBeCalled();

View file

@ -7,11 +7,12 @@
import { ElasticsearchClient } from '@kbn/core/server';
import { UpdateSLOParams, UpdateSLOResponse, updateSLOResponseSchema } from '@kbn/slo-schema';
import { isEqual } from 'lodash';
import { isEqual, pick } from 'lodash';
import {
getSLOTransformId,
SLO_DESTINATION_INDEX_PATTERN,
SLO_SUMMARY_DESTINATION_INDEX_PATTERN,
SLO_SUMMARY_ENRICH_POLICY_NAME,
SLO_SUMMARY_TEMP_INDEX_NAME,
} from '../../assets/constants';
import { SLO } from '../../domain/models';
@ -24,7 +25,8 @@ export class UpdateSLO {
constructor(
private repository: SLORepository,
private transformManager: TransformManager,
private esClient: ElasticsearchClient
private esClient: ElasticsearchClient,
private systemClient: ElasticsearchClient
) {}
public async execute(sloId: string, params: UpdateSLOParams): Promise<UpdateSLOResponse> {
@ -37,23 +39,38 @@ export class UpdateSLO {
return this.toResponse(originalSlo);
}
const fields = [
'indicator',
'groupBy',
'timeWindow',
'objective',
'budgetingMethod',
'settings',
];
const requireRevisionBump = !isEqual(pick(originalSlo, fields), pick(updatedSlo, fields));
updatedSlo = Object.assign(updatedSlo, {
updatedAt: new Date(),
revision: originalSlo.revision + 1,
revision: requireRevisionBump ? originalSlo.revision + 1 : originalSlo.revision,
});
validateSLO(updatedSlo);
const updatedSloTransformId = getSLOTransformId(updatedSlo.id, updatedSlo.revision);
await this.repository.save(updatedSlo);
await this.systemClient.enrich.executePolicy({ name: SLO_SUMMARY_ENRICH_POLICY_NAME });
if (!requireRevisionBump) {
return this.toResponse(updatedSlo);
}
try {
await this.transformManager.install(updatedSlo);
} catch (err) {
await this.repository.save(originalSlo);
await this.systemClient.enrich.executePolicy({ name: SLO_SUMMARY_ENRICH_POLICY_NAME });
throw err;
}
const updatedSloTransformId = getSLOTransformId(updatedSlo.id, updatedSlo.revision);
try {
await this.transformManager.preview(updatedSloTransformId);
await this.transformManager.start(updatedSloTransformId);
@ -61,6 +78,7 @@ export class UpdateSLO {
await Promise.all([
this.transformManager.uninstall(updatedSloTransformId),
this.repository.save(originalSlo),
this.systemClient.enrich.executePolicy({ name: SLO_SUMMARY_ENRICH_POLICY_NAME }),
]);
throw err;

View file

@ -6,6 +6,7 @@
*/
import expect from '@kbn/expect';
import { SLO_SUMMARY_ENRICH_POLICY_NAME } from '@kbn/observability-plugin/server/assets/constants';
import { FtrProviderContext } from '../../../ftr_provider_context';
export default ({ getPageObjects, getService }: FtrProviderContext) => {
@ -23,6 +24,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
before(async () => {
await log.debug('Creating test index');
try {
await es.ingest.deletePipeline({ id: '.slo-*' }, { ignore: [404] });
await es.enrich.deletePolicy({ name: SLO_SUMMARY_ENRICH_POLICY_NAME }, { ignore: [404] });
await es.indices.create({
index: INDEX_NAME,
body: {

View file

@ -6,6 +6,7 @@
*/
import expect from '@kbn/expect';
import { SLO_SUMMARY_ENRICH_POLICY_NAME } from '@kbn/observability-plugin/server/assets/constants';
import { FtrProviderContext } from '../../ftr_provider_context';
export default ({ getPageObjects, getService }: FtrProviderContext) => {
@ -15,6 +16,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
const browser = getService('browser');
const retry = getService('retry');
const security = getService('security');
const es = getService('es');
describe('Home page', function () {
before(async () => {
@ -94,6 +96,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
describe('Enrich policies', () => {
before(async () => {
await es.ingest.deletePipeline({ id: '.slo-*' }, { ignore: [404] });
await es.enrich.deletePolicy({ name: SLO_SUMMARY_ENRICH_POLICY_NAME }, { ignore: [404] });
});
it('renders the enrich policies tab', async () => {
// Navigate to the component templates tab
await pageObjects.indexManagement.changeTabs('enrich_policiesTab');

View file

@ -6,6 +6,7 @@
*/
import expect from '@kbn/expect';
import { SLO_SUMMARY_ENRICH_POLICY_NAME } from '@kbn/observability-plugin/server/assets/constants';
import { FtrProviderContext } from '../../../../ftr_provider_context';
export default ({ getPageObjects, getService }: FtrProviderContext) => {
@ -25,6 +26,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
before(async () => {
log.debug('Creating test index');
try {
await es.ingest.deletePipeline({ id: '.slo-*' }, { ignore: [404] });
await es.enrich.deletePolicy({ name: SLO_SUMMARY_ENRICH_POLICY_NAME }, { ignore: [404] });
await es.indices.create({
index: INDEX_NAME,
body: {