mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
# Backport This will backport the following commits from `main` to `8.8`: - [fix(slo): remove good status codes from apm availability (#157497)](https://github.com/elastic/kibana/pull/157497) <!--- Backport version: 8.9.7 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Kevin Delemme","email":"kevin.delemme@elastic.co"},"sourceCommit":{"committedDate":"2023-05-12T15:11:39Z","message":"fix(slo): remove good status codes from apm availability (#157497)","sha":"65a6f7435b13caf730721e61b12c4b735c11d7bd","branchLabelMapping":{"^v8.9.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team: Actionable Observability","backport:prev-minor","v8.9.0"],"number":157497,"url":"https://github.com/elastic/kibana/pull/157497","mergeCommit":{"message":"fix(slo): remove good status codes from apm availability (#157497)","sha":"65a6f7435b13caf730721e61b12c4b735c11d7bd"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v8.9.0","labelRegex":"^v8.9.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/157497","number":157497,"mergeCommit":{"message":"fix(slo): remove good status codes from apm availability (#157497)","sha":"65a6f7435b13caf730721e61b12c4b735c11d7bd"}}]}] BACKPORT--> Co-authored-by: Kevin Delemme <kevin.delemme@elastic.co>
This commit is contained in:
parent
aa7f4e40e5
commit
e5132c79d4
13 changed files with 21 additions and 202 deletions
|
@ -39,9 +39,6 @@ const apmTransactionErrorRateIndicatorSchema = t.type({
|
|||
index: t.string,
|
||||
}),
|
||||
t.partial({
|
||||
goodStatusCodes: t.array(
|
||||
t.union([t.literal('2xx'), t.literal('3xx'), t.literal('4xx'), t.literal('5xx')])
|
||||
),
|
||||
filter: t.string,
|
||||
}),
|
||||
]),
|
||||
|
|
|
@ -10,7 +10,7 @@ We currently support the following SLI:
|
|||
- APM Transaction Duration, known as APM Latency
|
||||
- Custom KQL
|
||||
|
||||
For the APM SLIs, customer can provide the service, environment, transaction name and type to configure them. For the **APM Latency** SLI, a threshold in milliseconds needs to be provided to discriminate the good and bad responses (events). For the **APM Availability** SLI, a list of good status codes needs to be provided to discriminate the good and bad responses (events). The API supports an optional kql filter to further filter the apm data.
|
||||
For the APM SLIs, customer can provide the service, environment, transaction name and type to configure them. For the **APM Latency** SLI, a threshold in milliseconds needs to be provided to discriminate the good and bad responses (events). For the **APM Availability** SLI, we use the `event.outcome` as a way to discriminate the good and the bad responses(events). The API supports an optional kql filter to further filter the apm data.
|
||||
|
||||
The **custom KQL** SLI requires an index pattern, an optional filter query, a numerator query, and denominator query. A custom 'timestampField' can be provided to override the default @timestamp field.
|
||||
|
||||
|
@ -69,7 +69,6 @@ curl --request POST \
|
|||
"service": "o11y-app",
|
||||
"transactionType": "request",
|
||||
"transactionName": "GET /api",
|
||||
"goodStatusCodes": ["2xx", "3xx", "4xx"],
|
||||
"index": "metrics-apm*"
|
||||
}
|
||||
},
|
||||
|
@ -105,7 +104,6 @@ curl --request POST \
|
|||
"service": "o11y-app",
|
||||
"transactionType": "request",
|
||||
"transactionName": "GET /api",
|
||||
"goodStatusCodes": ["2xx", "3xx", "4xx"],
|
||||
"index": "metrics-apm*"
|
||||
}
|
||||
},
|
||||
|
@ -143,7 +141,6 @@ curl --request POST \
|
|||
"service": "o11y-app",
|
||||
"transactionType": "request",
|
||||
"transactionName": "GET /api",
|
||||
"goodStatusCodes": ["2xx", "3xx", "4xx"],
|
||||
"index": "metrics-apm*"
|
||||
}
|
||||
},
|
||||
|
|
|
@ -424,15 +424,6 @@ components:
|
|||
description: The APM transaction name or "*"
|
||||
type: string
|
||||
example: GET /my/api
|
||||
goodStatusCodes:
|
||||
description: The status codes considered as good events. Default to 2xx, 3xx and 4xx
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
example:
|
||||
- 2xx
|
||||
- 3xx
|
||||
- 4xx
|
||||
filter:
|
||||
description: KQL query used for filtering the data
|
||||
type: string
|
||||
|
|
|
@ -32,15 +32,6 @@ properties:
|
|||
description: The APM transaction name or "*"
|
||||
type: string
|
||||
example: GET /my/api
|
||||
goodStatusCodes:
|
||||
description: The status codes considered as good events. Default to 2xx, 3xx and 4xx
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
example:
|
||||
- "2xx"
|
||||
- "3xx"
|
||||
- "4xx"
|
||||
filter:
|
||||
description: KQL query used for filtering the data
|
||||
type: string
|
||||
|
|
|
@ -17,7 +17,6 @@ export const buildApmAvailabilityIndicator = (
|
|||
service: 'o11y-app',
|
||||
transactionType: 'request',
|
||||
transactionName: 'GET /flaky',
|
||||
goodStatusCodes: ['2xx', '3xx', '4xx'],
|
||||
index: 'metrics-apm*',
|
||||
...params,
|
||||
},
|
||||
|
|
|
@ -6,15 +6,8 @@
|
|||
*/
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import {
|
||||
EuiComboBox,
|
||||
EuiComboBoxOptionOption,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiFormRow,
|
||||
EuiIconTip,
|
||||
} from '@elastic/eui';
|
||||
import { Controller, useFormContext } from 'react-hook-form';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { CreateSLOInput } from '@kbn/slo-schema';
|
||||
|
||||
|
@ -23,7 +16,7 @@ import { FieldSelector } from '../apm_common/field_selector';
|
|||
import { QueryBuilder } from '../common/query_builder';
|
||||
|
||||
export function ApmAvailabilityIndicatorTypeForm() {
|
||||
const { control, setValue, watch, getFieldState } = useFormContext<CreateSLOInput>();
|
||||
const { control, setValue, watch } = useFormContext<CreateSLOInput>();
|
||||
const { data: apmIndex } = useFetchApmIndex();
|
||||
useEffect(() => {
|
||||
setValue('indicator.params.index', apmIndex);
|
||||
|
@ -104,65 +97,6 @@ export function ApmAvailabilityIndicatorTypeForm() {
|
|||
</EuiFlexGroup>
|
||||
|
||||
<EuiFlexGroup direction="row" gutterSize="l">
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow
|
||||
label={
|
||||
<span>
|
||||
{i18n.translate('xpack.observability.slo.sloEdit.apmAvailability.goodStatusCodes', {
|
||||
defaultMessage: 'Good status codes',
|
||||
})}{' '}
|
||||
<EuiIconTip
|
||||
content={i18n.translate(
|
||||
'xpack.observability.slo.sloEdit.apmAvailability.goodStatusCodes.tooltip',
|
||||
{
|
||||
defaultMessage:
|
||||
'Configure the HTTP status codes defining the "good" or "successful" requests for the SLO.',
|
||||
}
|
||||
)}
|
||||
position="top"
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
isInvalid={getFieldState('indicator.params.goodStatusCodes').invalid}
|
||||
>
|
||||
<Controller
|
||||
shouldUnregister
|
||||
name="indicator.params.goodStatusCodes"
|
||||
control={control}
|
||||
defaultValue={['2xx', '3xx', '4xx']}
|
||||
rules={{ required: true }}
|
||||
render={({ field: { ref, ...field }, fieldState }) => (
|
||||
<EuiComboBox
|
||||
{...field}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.observability.slo.sloEdit.apmAvailability.goodStatusCodes.placeholder',
|
||||
{
|
||||
defaultMessage: 'Select the good status codes',
|
||||
}
|
||||
)}
|
||||
placeholder={i18n.translate(
|
||||
'xpack.observability.slo.sloEdit.apmAvailability.goodStatusCodes.placeholder',
|
||||
{
|
||||
defaultMessage: 'Select the good status codes',
|
||||
}
|
||||
)}
|
||||
isInvalid={fieldState.invalid}
|
||||
options={generateStatusCodeOptions(['2xx', '3xx', '4xx', '5xx'])}
|
||||
selectedOptions={generateStatusCodeOptions(field.value)}
|
||||
onChange={(selected: EuiComboBoxOptionOption[]) => {
|
||||
if (selected.length) {
|
||||
return field.onChange(selected.map((opts) => opts.value));
|
||||
}
|
||||
|
||||
field.onChange([]);
|
||||
}}
|
||||
isClearable
|
||||
data-test-subj="sloEditApmAvailabilityGoodStatusCodesSelector"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<QueryBuilder
|
||||
control={control}
|
||||
|
@ -193,11 +127,3 @@ export function ApmAvailabilityIndicatorTypeForm() {
|
|||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
|
||||
function generateStatusCodeOptions(codes: string[] = []) {
|
||||
return codes.map((code) => ({
|
||||
label: code,
|
||||
value: code,
|
||||
'data-test-subj': `${code}Option`,
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ export function SloEditFormDescriptionSection() {
|
|||
}
|
||||
}}
|
||||
isClearable
|
||||
data-test-subj="sloEditApmAvailabilityGoodStatusCodesSelector"
|
||||
data-test-subj="sloEditTagsSelector"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
|
|
@ -57,7 +57,7 @@ export function useSectionFormValidation({ getFieldState, getValues, formState,
|
|||
'indicator.params.transactionName',
|
||||
] as const
|
||||
).every((field) => !getFieldState(field, formState).invalid && getValues(field) !== '') &&
|
||||
(['indicator.params.index', 'indicator.params.goodStatusCodes'] as const).every(
|
||||
(['indicator.params.index'] as const).every(
|
||||
(field) => !getFieldState(field, formState).invalid
|
||||
);
|
||||
break;
|
||||
|
|
|
@ -34,7 +34,6 @@ export const createAPMTransactionErrorRateIndicator = (
|
|||
service: 'irrelevant',
|
||||
transactionName: 'irrelevant',
|
||||
transactionType: 'irrelevant',
|
||||
goodStatusCodes: ['2xx', '3xx', '4xx'],
|
||||
index: 'metrics-apm*',
|
||||
...params,
|
||||
},
|
||||
|
|
|
@ -53,7 +53,6 @@ describe('GetSLO', () => {
|
|||
service: 'irrelevant',
|
||||
transactionName: 'irrelevant',
|
||||
transactionType: 'irrelevant',
|
||||
goodStatusCodes: ['2xx', '3xx', '4xx'],
|
||||
index: 'metrics-apm*',
|
||||
},
|
||||
type: 'sli.apm.transactionErrorRate',
|
||||
|
|
|
@ -181,23 +181,11 @@ Object {
|
|||
"slo.numerator": Object {
|
||||
"filter": Object {
|
||||
"bool": Object {
|
||||
"should": Array [
|
||||
Object {
|
||||
"match": Object {
|
||||
"transaction.result": "HTTP 2xx",
|
||||
},
|
||||
"should": Object {
|
||||
"match": Object {
|
||||
"event.outcome": "success",
|
||||
},
|
||||
Object {
|
||||
"match": Object {
|
||||
"transaction.result": "HTTP 3xx",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"match": Object {
|
||||
"transaction.result": "HTTP 4xx",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -329,23 +317,11 @@ Object {
|
|||
"slo.numerator": Object {
|
||||
"filter": Object {
|
||||
"bool": Object {
|
||||
"should": Array [
|
||||
Object {
|
||||
"match": Object {
|
||||
"transaction.result": "HTTP 2xx",
|
||||
},
|
||||
"should": Object {
|
||||
"match": Object {
|
||||
"event.outcome": "success",
|
||||
},
|
||||
Object {
|
||||
"match": Object {
|
||||
"transaction.result": "HTTP 3xx",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"match": Object {
|
||||
"transaction.result": "HTTP 4xx",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -453,36 +429,3 @@ Object {
|
|||
"transform_id": Any<String>,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`APM Transaction Error Rate Transform Generator uses default values when 'good_status_codes' is not specified 1`] = `
|
||||
Object {
|
||||
"slo.denominator": Object {
|
||||
"value_count": Object {
|
||||
"field": "transaction.duration.histogram",
|
||||
},
|
||||
},
|
||||
"slo.numerator": Object {
|
||||
"filter": Object {
|
||||
"bool": Object {
|
||||
"should": Array [
|
||||
Object {
|
||||
"match": Object {
|
||||
"transaction.result": "HTTP 2xx",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"match": Object {
|
||||
"transaction.result": "HTTP 3xx",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"match": Object {
|
||||
"transaction.result": "HTTP 4xx",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -44,15 +44,6 @@ describe('APM Transaction Error Rate Transform Generator', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("uses default values when 'good_status_codes' is not specified", async () => {
|
||||
const anSLO = createSLO({
|
||||
indicator: createAPMTransactionErrorRateIndicator({ goodStatusCodes: [] }),
|
||||
});
|
||||
const transform = generator.getTransformParams(anSLO);
|
||||
|
||||
expect(transform.pivot?.aggregations).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not include the query filter when params are '*'", async () => {
|
||||
const anSLO = createSLO({
|
||||
indicator: createAPMTransactionErrorRateIndicator({
|
||||
|
|
|
@ -24,9 +24,6 @@ import { APMTransactionErrorRateIndicator, SLO } from '../../../domain/models';
|
|||
import { Query } from './types';
|
||||
import { parseIndex } from './common';
|
||||
|
||||
const ALLOWED_STATUS_CODES = ['2xx', '3xx', '4xx', '5xx'];
|
||||
const DEFAULT_GOOD_STATUS_CODES = ['2xx', '3xx', '4xx'];
|
||||
|
||||
export class ApmTransactionErrorRateTransformGenerator extends TransformGenerator {
|
||||
public getTransformParams(slo: SLO): TransformPutTransformRequest {
|
||||
if (!apmTransactionErrorRateIndicatorSchema.is(slo.indicator)) {
|
||||
|
@ -39,7 +36,7 @@ export class ApmTransactionErrorRateTransformGenerator extends TransformGenerato
|
|||
this.buildSource(slo, slo.indicator),
|
||||
this.buildDestination(),
|
||||
this.buildGroupBy(slo),
|
||||
this.buildAggregations(slo, slo.indicator),
|
||||
this.buildAggregations(slo),
|
||||
this.buildSettings(slo)
|
||||
);
|
||||
}
|
||||
|
@ -119,14 +116,16 @@ export class ApmTransactionErrorRateTransformGenerator extends TransformGenerato
|
|||
};
|
||||
}
|
||||
|
||||
private buildAggregations(slo: SLO, indicator: APMTransactionErrorRateIndicator) {
|
||||
const goodStatusCodesFilter = this.getGoodStatusCodesFilter(indicator.params.goodStatusCodes);
|
||||
|
||||
private buildAggregations(slo: SLO) {
|
||||
return {
|
||||
'slo.numerator': {
|
||||
filter: {
|
||||
bool: {
|
||||
should: goodStatusCodesFilter,
|
||||
should: {
|
||||
match: {
|
||||
'event.outcome': 'success',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -148,17 +147,4 @@ export class ApmTransactionErrorRateTransformGenerator extends TransformGenerato
|
|||
}),
|
||||
};
|
||||
}
|
||||
|
||||
private getGoodStatusCodesFilter(goodStatusCodes: string[] | undefined) {
|
||||
let statusCodes = goodStatusCodes?.filter((code) => ALLOWED_STATUS_CODES.includes(code));
|
||||
if (statusCodes === undefined || statusCodes.length === 0) {
|
||||
statusCodes = DEFAULT_GOOD_STATUS_CODES;
|
||||
}
|
||||
|
||||
return statusCodes.map((code) => ({
|
||||
match: {
|
||||
'transaction.result': `HTTP ${code}`,
|
||||
},
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue