[APM] alert details - add alert start annotation to all visualizations (#184677)

## Summary

Summarize your PR. If it involves visual changes include a screenshot or
gif.

SLO APM latency alert details page

![image](8a205f5d-00ea-4dce-9d66-a51d284caaa9)

SLO APM error rate alert details page

![image](d7ea10d4-d640-4d9e-8ca5-9c7bed2ba279)

APM latency alert details page

![image](2b4e0c6c-a481-41f7-848b-87836565905d)

### Testing

1. Create an APM latency rule that fires. Navigate to the alert details
page and confirm the annotations appear correctly.
2. Create an SLO burn rate rule for the APM latency SLI that fires.
Navigate to the alert details page and confirm the annotations appear
correctly
3. Create an SLO burn rate rule for the APM error rate SLI that fires.
Navigate to the alert details page and confirm the annotations appear
correctly

---------

Co-authored-by: Carlos Crespo <crespocarlos@users.noreply.github.com>
This commit is contained in:
Dominique Clarke 2024-06-11 09:22:14 -04:00 committed by GitHub
parent 7e344a766d
commit 9e52d98d2b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 101 additions and 47 deletions

View file

@ -7,7 +7,6 @@
/* Error Rate */
import React from 'react';
import chroma from 'chroma-js';
import {
EuiFlexItem,
EuiPanel,
@ -16,13 +15,11 @@ import {
EuiIconTip,
RecursivePartial,
useEuiTheme,
transparentize,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { BoolQuery } from '@kbn/es-query';
import { UI_SETTINGS } from '@kbn/data-plugin/public';
import { Theme } from '@elastic/charts';
import { AlertActiveTimeRangeAnnotation, AlertAnnotation } from '@kbn/observability-alert-details';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { DEFAULT_DATE_FORMAT } from './constants';
import { useFetcher } from '../../../../hooks/use_fetcher';
@ -36,6 +33,7 @@ import { usePreferredDataSourceAndBucketSize } from '../../../../hooks/use_prefe
import { ApmDocumentType } from '../../../../../common/document_type';
import { TransactionTypeSelect } from './transaction_type_select';
import { ViewInAPMButton } from './view_in_apm_button';
import { getAlertStartAnnotation } from './get_alert_start_annotation';
type ErrorRate =
APIReturnType<'GET /internal/apm/services/{serviceName}/transactions/charts/error_rate'>;
@ -75,12 +73,12 @@ function FailedTransactionChart({
environment: string;
start: string;
end: string;
alertStart?: number;
alertEnd?: number;
comparisonChartTheme: RecursivePartial<Theme>;
timeZone: string;
kuery?: string;
filters?: BoolQuery;
alertStart?: number;
alertEnd?: number;
}) {
const { euiTheme } = useEuiTheme();
const {
@ -151,25 +149,14 @@ function FailedTransactionChart({
const showTransactionTypeSelect = setTransactionType && transactionTypes;
const getFailedTransactionChartAdditionalData = () => {
if (alertStart) {
return [
<AlertActiveTimeRangeAnnotation
alertStart={alertStart}
alertEnd={alertEnd}
color={chroma(transparentize('#F04E981A', 0.2)).hex().toUpperCase()}
id={'alertActiveRect'}
key={'alertActiveRect'}
/>,
<AlertAnnotation
key={'alertAnnotationStart'}
id={'alertAnnotationStart'}
alertStart={alertStart}
color={euiTheme.colors.danger}
dateFormat={
(uiSettings && uiSettings.get(UI_SETTINGS.DATE_FORMAT)) || DEFAULT_DATE_FORMAT
}
/>,
];
return getAlertStartAnnotation({
alertStart,
alertEnd,
color: euiTheme.colors.danger,
dateFormat: (uiSettings && uiSettings.get(UI_SETTINGS.DATE_FORMAT)) || DEFAULT_DATE_FORMAT,
});
}
return [];
};
return (
<EuiFlexItem>

View file

@ -0,0 +1,37 @@
/*
* 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 React from 'react';
import { AlertActiveTimeRangeAnnotation, AlertAnnotation } from '@kbn/observability-alert-details';
export function getAlertStartAnnotation({
alertStart,
alertEnd,
dateFormat,
color,
}: {
alertStart: number;
alertEnd?: number;
dateFormat: string;
color: string;
}) {
return [
<AlertActiveTimeRangeAnnotation
alertStart={alertStart}
alertEnd={alertEnd}
color={color}
id="alertActiveRect"
key="alertActiveRect"
/>,
<AlertAnnotation
key="alertAnnotationStart"
id="alertAnnotationStart"
alertStart={alertStart}
color={color}
dateFormat={dateFormat}
/>,
];
}

View file

@ -4,7 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import moment from 'moment';
import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { formatAlertEvaluationValue } from '@kbn/observability-plugin/public';
@ -145,6 +145,8 @@ export function AlertDetailsAppSection({
);
}
const alertEnd = alert.fields[ALERT_END] ? moment(alert.fields[ALERT_END]).valueOf() : undefined;
return (
<EuiFlexGroup direction="column" gutterSize="s">
<TimeRangeMetadataContextProvider
@ -179,6 +181,8 @@ export function AlertDetailsAppSection({
environment={environment}
start={from}
end={to}
alertStart={alert.start}
alertEnd={alertEnd}
comparisonChartTheme={comparisonChartTheme}
comparisonEnabled={false}
offset={''}
@ -191,6 +195,8 @@ export function AlertDetailsAppSection({
environment={environment}
start={from}
end={to}
alertStart={alert.start}
alertEnd={alertEnd}
comparisonChartTheme={comparisonChartTheme}
timeZone={timeZone}
/>

View file

@ -15,10 +15,8 @@ import { getDurationFormatter } from '@kbn/observability-plugin/common';
import { ALERT_RULE_TYPE_ID, ALERT_EVALUATION_THRESHOLD, ALERT_END } from '@kbn/rule-data-utils';
import type { TopAlert } from '@kbn/observability-plugin/public';
import {
AlertActiveTimeRangeAnnotation,
AlertThresholdAnnotation,
AlertThresholdTimeRangeRect,
AlertAnnotation,
} from '@kbn/observability-alert-details';
import { useEuiTheme } from '@elastic/eui';
import { useKibana } from '@kbn/kibana-react-plugin/public';
@ -41,6 +39,7 @@ import { usePreferredDataSourceAndBucketSize } from '../../../../hooks/use_prefe
import { DEFAULT_DATE_FORMAT } from './constants';
import { TransactionTypeSelect } from './transaction_type_select';
import { ViewInAPMButton } from './view_in_apm_button';
import { getAlertStartAnnotation } from './get_alert_start_annotation';
function LatencyChart({
alert,
@ -160,26 +159,20 @@ function LatencyChart({
isLatencyThresholdRuleType(alert.fields[ALERT_RULE_TYPE_ID]) ||
customAlertEvaluationThreshold
) {
return [
<AlertActiveTimeRangeAnnotation
alertStart={alert.start}
alertEnd={alertEnd}
color={euiTheme.colors.danger}
id={'alertActiveRect'}
key={'alertActiveRect'}
/>,
<AlertAnnotation
key={'alertAnnotationStart'}
id={'alertAnnotationStart'}
alertStart={alert.start}
color={euiTheme.colors.danger}
dateFormat={
(uiSettings && uiSettings.get(UI_SETTINGS.DATE_FORMAT)) || DEFAULT_DATE_FORMAT
}
/>,
...alertEvalThresholdChartData,
];
return [...alertEvalThresholdChartData];
}
return [];
};
const getLatencyChartAlertStartData = () => {
if (alert.start) {
return getAlertStartAnnotation({
alertStart: alert.start,
alertEnd,
color: euiTheme.colors.danger,
dateFormat: (uiSettings && uiSettings.get(UI_SETTINGS.DATE_FORMAT)) || DEFAULT_DATE_FORMAT,
});
}
return [];
};
const memoizedData = useMemo(
() =>
@ -247,7 +240,7 @@ function LatencyChart({
</EuiFlexGroup>
<TimeseriesChart
id="latencyChart"
annotations={getLatencyChartAdditionalData()}
annotations={[...getLatencyChartAdditionalData(), ...getLatencyChartAlertStartData()]}
height={200}
comparisonEnabled={comparisonEnabled}
offset={offset}

View file

@ -8,6 +8,7 @@
import React from 'react';
import { Theme } from '@elastic/charts';
import { BoolQuery } from '@kbn/es-query';
import { UI_SETTINGS } from '@kbn/data-plugin/public';
import {
RecursivePartial,
EuiFlexItem,
@ -15,7 +16,9 @@ import {
EuiFlexGroup,
EuiTitle,
EuiIconTip,
useEuiTheme,
} from '@elastic/eui';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { i18n } from '@kbn/i18n';
import { ChartType, getTimeSeriesColor } from '../../../shared/charts/helper/get_timeseries_color';
@ -26,6 +29,8 @@ import { ApmDocumentType } from '../../../../../common/document_type';
import { asExactTransactionRate } from '../../../../../common/utils/formatters';
import { TransactionTypeSelect } from './transaction_type_select';
import { ViewInAPMButton } from './view_in_apm_button';
import { getAlertStartAnnotation } from './get_alert_start_annotation';
import { DEFAULT_DATE_FORMAT } from './constants';
const INITIAL_STATE = {
currentPeriod: [],
@ -40,6 +45,8 @@ function ThroughputChart({
environment,
start,
end,
alertStart,
alertEnd,
comparisonChartTheme,
comparisonEnabled,
offset,
@ -55,6 +62,8 @@ function ThroughputChart({
environment: string;
start: string;
end: string;
alertStart?: number;
alertEnd?: number;
comparisonChartTheme: RecursivePartial<Theme>;
comparisonEnabled: boolean;
offset: string;
@ -62,6 +71,10 @@ function ThroughputChart({
kuery?: string;
filters?: BoolQuery;
}) {
const { euiTheme } = useEuiTheme();
const {
services: { uiSettings },
} = useKibana();
const preferred = usePreferredDataSourceAndBucketSize({
start,
end,
@ -129,6 +142,17 @@ function ThroughputChart({
]
: []),
];
const getThroughputChartAdditionalData = () => {
if (alertStart) {
return getAlertStartAnnotation({
alertStart,
alertEnd,
color: euiTheme.colors.danger,
dateFormat: (uiSettings && uiSettings.get(UI_SETTINGS.DATE_FORMAT)) || DEFAULT_DATE_FORMAT,
});
}
return [];
};
const showTransactionTypeSelect = setTransactionType && transactionTypes;
@ -190,6 +214,7 @@ function ThroughputChart({
timeseries={timeseriesThroughput}
yLabelFormat={asExactTransactionRate}
timeZone={timeZone}
annotations={getThroughputChartAdditionalData()}
/>
</EuiPanel>
</EuiFlexItem>

View file

@ -4,8 +4,9 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import moment from 'moment';
import React from 'react';
import { ALERT_END } from '@kbn/rule-data-utils';
import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values';
import ThroughputChart from '../../../components/alerting/ui_components/alert_details_app_section/throughput_chart';
import { EmbeddableApmAlertingVizProps } from '../types';
@ -15,6 +16,7 @@ import { ServiceNameCallout } from '../service_name_callout';
export function APMAlertingThroughputChart({
rule,
alert,
rangeFrom = 'now-15m',
rangeTo = 'now',
transactionName,
@ -46,6 +48,8 @@ export function APMAlertingThroughputChart({
return <ServiceNameCallout />;
}
const alertEnd = alert.fields[ALERT_END] ? moment(alert.fields[ALERT_END]).valueOf() : undefined;
return (
<ThroughputChart
transactionType={currentTransactionType}
@ -56,6 +60,8 @@ export function APMAlertingThroughputChart({
environment={environment}
start={rangeFrom}
end={rangeTo}
alertStart={alert.start}
alertEnd={alertEnd}
comparisonChartTheme={comparisonChartTheme}
timeZone={timeZone}
comparisonEnabled={false}