Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[SLO] Add burn rate windows to SLO detail page (#159750)
## Summary This PR adds a burn rate visualization to the overview tab of the SLO Detail page. This PR also includes a fix for fetching the index pattern fields hook; it uses the DataViews service to fetch the fields instead of the internal API. <img width="1170" alt="image" src="https://github.com/elastic/kibana/assets/41702/41057791-880e-4cc8-a0c7-02a0f18aaeca"> ### All good <img width="1141" alt="image" src="https://github.com/elastic/kibana/assets/41702/3ec07efa-e35a-4251-87f3-7ddc836171b7"> ### Degrading <img width="1141" alt="image" src="https://github.com/elastic/kibana/assets/41702/a6d347be-7b55-404e-99a1-14ad4a38ad36"> ### EVERYTHING IS BURNING 🔥 <img width="1141" alt="image" src="https://github.com/elastic/kibana/assets/41702/9ed05875-b907-4a57-8387-a094876dd35e"> ### Recovering in the dark <img width="1151" alt="image" src="https://github.com/elastic/kibana/assets/41702/f2999c7a-f97b-474c-8146-4565445df892"> ### No data <img width="1141" alt="image" src="https://github.com/elastic/kibana/assets/41702/675a65a4-91b1-4de3-9f51-b65760efbb66">
- Loading branch information
1 parent
7153359
commit c0d3a93
Showing
9 changed files
with
534 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_burn_rates.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* | ||
* 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 { | ||
QueryObserverResult, | ||
RefetchOptions, | ||
RefetchQueryFilters, | ||
useQuery, | ||
} from '@tanstack/react-query'; | ||
import { GetSLOBurnRatesResponse } from '@kbn/slo-schema'; | ||
import { useKibana } from '../../utils/kibana_react'; | ||
import { sloKeys } from './query_key_factory'; | ||
|
||
export interface UseFetchSloBurnRatesResponse { | ||
isInitialLoading: boolean; | ||
isLoading: boolean; | ||
isRefetching: boolean; | ||
isSuccess: boolean; | ||
isError: boolean; | ||
data: GetSLOBurnRatesResponse | undefined; | ||
refetch: <TPageData>( | ||
options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined | ||
) => Promise<QueryObserverResult<GetSLOBurnRatesResponse | undefined, unknown>>; | ||
} | ||
|
||
const LONG_REFETCH_INTERVAL = 1000 * 60; // 1 minute | ||
|
||
interface UseFetchSloBurnRatesParams { | ||
sloId: string; | ||
windows: Array<{ name: string; duration: string }>; | ||
shouldRefetch?: boolean; | ||
} | ||
|
||
export function useFetchSloBurnRates({ | ||
sloId, | ||
windows, | ||
shouldRefetch, | ||
}: UseFetchSloBurnRatesParams): UseFetchSloBurnRatesResponse { | ||
const { http } = useKibana().services; | ||
const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data, refetch } = useQuery( | ||
{ | ||
queryKey: sloKeys.burnRates(sloId), | ||
queryFn: async ({ signal }) => { | ||
try { | ||
const response = await http.post<GetSLOBurnRatesResponse>( | ||
`/internal/observability/slos/${sloId}/_burn_rates`, | ||
{ | ||
body: JSON.stringify({ windows }), | ||
signal, | ||
} | ||
); | ||
|
||
return response; | ||
} catch (error) { | ||
// ignore error | ||
} | ||
}, | ||
refetchInterval: shouldRefetch ? LONG_REFETCH_INTERVAL : undefined, | ||
refetchOnWindowFocus: false, | ||
keepPreviousData: true, | ||
} | ||
); | ||
|
||
return { | ||
data, | ||
refetch, | ||
isLoading, | ||
isRefetching, | ||
isInitialLoading, | ||
isSuccess, | ||
isError, | ||
}; | ||
} |
127 changes: 127 additions & 0 deletions
127
x-pack/plugins/observability/public/pages/slo_details/components/burn_rate_window.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
/* | ||
* 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 { | ||
EuiSpacer, | ||
EuiFlexGroup, | ||
EuiPanel, | ||
EuiFlexItem, | ||
EuiStat, | ||
EuiTextColor, | ||
EuiText, | ||
EuiIconTip, | ||
} from '@elastic/eui'; | ||
import numeral from '@elastic/numeral'; | ||
import { i18n } from '@kbn/i18n'; | ||
|
||
export interface BurnRateWindowParams { | ||
title: string; | ||
target: number; | ||
longWindow: { | ||
label: string; | ||
burnRate: number | null; | ||
sli: number | null; | ||
}; | ||
shortWindow: { | ||
label: string; | ||
burnRate: number | null; | ||
sli: number | null; | ||
}; | ||
isLoading?: boolean; | ||
size?: 'xxxs' | 'xxs' | 'xs' | 's' | 'm' | 'l'; | ||
} | ||
|
||
const SUBDUED = 'subdued'; | ||
const DANGER = 'danger'; | ||
const SUCCESS = 'success'; | ||
const WARNING = 'warning'; | ||
|
||
function getColorBasedOnBurnRate(target: number, burnRate: number | null, sli: number | null) { | ||
if (burnRate === null || sli === null || sli < 0) { | ||
return SUBDUED; | ||
} | ||
if (burnRate > target) { | ||
return DANGER; | ||
} | ||
return SUCCESS; | ||
} | ||
|
||
export function BurnRateWindow({ | ||
title, | ||
target, | ||
longWindow, | ||
shortWindow, | ||
isLoading, | ||
size = 's', | ||
}: BurnRateWindowParams) { | ||
const longWindowColor = getColorBasedOnBurnRate(target, longWindow.burnRate, longWindow.sli); | ||
const shortWindowColor = getColorBasedOnBurnRate(target, shortWindow.burnRate, shortWindow.sli); | ||
|
||
const overallColor = | ||
longWindowColor === DANGER && shortWindowColor === DANGER | ||
? DANGER | ||
: [longWindowColor, shortWindowColor].includes(DANGER) | ||
? WARNING | ||
: longWindowColor === SUBDUED && shortWindowColor === SUBDUED | ||
? SUBDUED | ||
: SUCCESS; | ||
|
||
const isLongWindowValid = | ||
longWindow.burnRate != null && longWindow.sli != null && longWindow.sli >= 0; | ||
|
||
const isShortWindowValid = | ||
shortWindow.burnRate != null && shortWindow.sli != null && shortWindow.sli >= 0; | ||
|
||
return ( | ||
<EuiPanel color={overallColor}> | ||
<EuiText color={overallColor}> | ||
<h5> | ||
{title} | ||
<EuiIconTip | ||
content={i18n.translate('xpack.observability.slo.burnRateWindow.thresholdTip', { | ||
defaultMessage: 'Threshold is {target}x', | ||
values: { target }, | ||
})} | ||
position="top" | ||
/> | ||
</h5> | ||
</EuiText> | ||
<EuiSpacer size="xs" /> | ||
<EuiFlexGroup> | ||
<EuiFlexItem> | ||
<EuiStat | ||
title={isLongWindowValid ? `${numeral(longWindow.burnRate).format('0.[00]')}x` : '--'} | ||
titleColor={longWindowColor} | ||
titleSize={size} | ||
textAlign="left" | ||
isLoading={isLoading} | ||
description={ | ||
<EuiTextColor color={longWindowColor}> | ||
<span>{longWindow.label}</span> | ||
</EuiTextColor> | ||
} | ||
/> | ||
</EuiFlexItem> | ||
<EuiFlexItem> | ||
<EuiStat | ||
title={isShortWindowValid ? `${numeral(shortWindow.burnRate).format('0.[00]')}x` : '--'} | ||
titleColor={shortWindowColor} | ||
titleSize={size} | ||
textAlign="left" | ||
isLoading={isLoading} | ||
description={ | ||
<EuiTextColor color={shortWindowColor}> | ||
<span>{shortWindow.label}</span> | ||
</EuiTextColor> | ||
} | ||
/> | ||
</EuiFlexItem> | ||
</EuiFlexGroup> | ||
</EuiPanel> | ||
); | ||
} |
Oops, something went wrong.