mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[UX] Improve page-load axis (#78392)
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
29da04551d
commit
07ebb81a79
15 changed files with 357 additions and 74 deletions
|
@ -36,7 +36,7 @@ Then(`breakdown series should appear in chart`, () => {
|
||||||
|
|
||||||
cy.get('div.echLegendItem__label', DEFAULT_TIMEOUT).should(
|
cy.get('div.echLegendItem__label', DEFAULT_TIMEOUT).should(
|
||||||
'have.text',
|
'have.text',
|
||||||
'ChromeChrome Mobile WebViewSafariFirefoxMobile SafariChrome MobileChrome Mobile iOSOverall'
|
'OverallChromeChrome Mobile WebViewSafariFirefoxMobile SafariChrome MobileChrome Mobile iOS'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -26,7 +26,7 @@ Given(`a user browses the APM UI application for RUM Data`, () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Then(`should have correct client metrics`, () => {
|
Then(`should have correct client metrics`, () => {
|
||||||
const metrics = ['4 ms', '0.06 s', '55 '];
|
const metrics = ['4 ms', '58 ms', '55'];
|
||||||
|
|
||||||
verifyClientMetrics(metrics, true);
|
verifyClientMetrics(metrics, true);
|
||||||
});
|
});
|
||||||
|
|
|
@ -56,7 +56,7 @@ Then(/^it filters the client metrics "([^"]*)"$/, (filterName) => {
|
||||||
cy.get('.euiStat__title-isLoading').should('not.be.visible');
|
cy.get('.euiStat__title-isLoading').should('not.be.visible');
|
||||||
|
|
||||||
const data =
|
const data =
|
||||||
filterName === 'os' ? ['5 ms', '0.06 s', '8 '] : ['4 ms', '0.05 s', '28 '];
|
filterName === 'os' ? ['5 ms', '64 ms', '8'] : ['4 ms', '55 ms', '28'];
|
||||||
|
|
||||||
verifyClientMetrics(data, true);
|
verifyClientMetrics(data, true);
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ When('the user changes the selected percentile', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Then(`it displays client metric related to that percentile`, () => {
|
Then(`it displays client metric related to that percentile`, () => {
|
||||||
const metrics = ['14 ms', '0.13 s', '55 '];
|
const metrics = ['14 ms', '131 ms', '55'];
|
||||||
|
|
||||||
verifyClientMetrics(metrics, false);
|
verifyClientMetrics(metrics, false);
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ When('the user changes the selected service name', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Then(`it displays relevant client metrics`, () => {
|
Then(`it displays relevant client metrics`, () => {
|
||||||
const metrics = ['4 ms', '0.06 s', '55 '];
|
const metrics = ['4 ms', '58 ms', '55'];
|
||||||
|
|
||||||
verifyClientMetrics(metrics, false);
|
verifyClientMetrics(metrics, false);
|
||||||
});
|
});
|
||||||
|
|
|
@ -88,6 +88,10 @@ export function PageLoadDistChart({
|
||||||
|
|
||||||
const [darkMode] = useUiSetting$<boolean>('theme:darkMode');
|
const [darkMode] = useUiSetting$<boolean>('theme:darkMode');
|
||||||
|
|
||||||
|
const euiChartTheme = darkMode
|
||||||
|
? EUI_CHARTS_THEME_DARK
|
||||||
|
: EUI_CHARTS_THEME_LIGHT;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChartWrapper
|
<ChartWrapper
|
||||||
loading={loading || breakdownLoading}
|
loading={loading || breakdownLoading}
|
||||||
|
@ -97,11 +101,7 @@ export function PageLoadDistChart({
|
||||||
<PageLoadChart>
|
<PageLoadChart>
|
||||||
<Settings
|
<Settings
|
||||||
baseTheme={darkMode ? DARK_THEME : LIGHT_THEME}
|
baseTheme={darkMode ? DARK_THEME : LIGHT_THEME}
|
||||||
theme={
|
theme={euiChartTheme.theme}
|
||||||
darkMode
|
|
||||||
? EUI_CHARTS_THEME_DARK.theme
|
|
||||||
: EUI_CHARTS_THEME_LIGHT.theme
|
|
||||||
}
|
|
||||||
onBrushEnd={onBrushEnd}
|
onBrushEnd={onBrushEnd}
|
||||||
tooltip={tooltipProps}
|
tooltip={tooltipProps}
|
||||||
showLegend
|
showLegend
|
||||||
|
@ -116,9 +116,10 @@ export function PageLoadDistChart({
|
||||||
id="left"
|
id="left"
|
||||||
title={I18LABELS.percPageLoaded}
|
title={I18LABELS.percPageLoaded}
|
||||||
position={Position.Left}
|
position={Position.Left}
|
||||||
tickFormat={(d) => numeral(d).format('0.0') + '%'}
|
labelFormat={(d) => d + ' %'}
|
||||||
/>
|
/>
|
||||||
<LineSeries
|
<LineSeries
|
||||||
|
sortIndex={0}
|
||||||
fit={Fit.Linear}
|
fit={Fit.Linear}
|
||||||
id={'PagesPercentage'}
|
id={'PagesPercentage'}
|
||||||
name={I18LABELS.overall}
|
name={I18LABELS.overall}
|
||||||
|
@ -126,7 +127,12 @@ export function PageLoadDistChart({
|
||||||
yScaleType={ScaleType.Linear}
|
yScaleType={ScaleType.Linear}
|
||||||
data={data?.pageLoadDistribution ?? []}
|
data={data?.pageLoadDistribution ?? []}
|
||||||
curve={CurveType.CURVE_CATMULL_ROM}
|
curve={CurveType.CURVE_CATMULL_ROM}
|
||||||
lineSeriesStyle={{ point: { visible: false } }}
|
lineSeriesStyle={{
|
||||||
|
point: { visible: false },
|
||||||
|
line: { strokeWidth: 3 },
|
||||||
|
}}
|
||||||
|
color={euiChartTheme.theme.colors?.vizColors?.[1]}
|
||||||
|
tickFormat={(d) => numeral(d).format('0.0') + ' %'}
|
||||||
/>
|
/>
|
||||||
{breakdown && (
|
{breakdown && (
|
||||||
<BreakdownSeries
|
<BreakdownSeries
|
||||||
|
|
|
@ -71,6 +71,8 @@ export function PageViewsChart({ data, loading }: Props) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const hasBreakdowns = !!data?.topItems?.length;
|
||||||
|
|
||||||
const breakdownAccessors = data?.topItems?.length ? data?.topItems : ['y'];
|
const breakdownAccessors = data?.topItems?.length ? data?.topItems : ['y'];
|
||||||
|
|
||||||
const [darkMode] = useUiSetting$<boolean>('theme:darkMode');
|
const [darkMode] = useUiSetting$<boolean>('theme:darkMode');
|
||||||
|
@ -83,17 +85,17 @@ export function PageViewsChart({ data, loading }: Props) {
|
||||||
return yAccessor;
|
return yAccessor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const euiChartTheme = darkMode
|
||||||
|
? EUI_CHARTS_THEME_DARK
|
||||||
|
: EUI_CHARTS_THEME_LIGHT;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChartWrapper loading={loading} height="calc(100% - 72px)">
|
<ChartWrapper loading={loading} height="calc(100% - 72px)">
|
||||||
{(!loading || data) && (
|
{(!loading || data) && (
|
||||||
<Chart>
|
<Chart>
|
||||||
<Settings
|
<Settings
|
||||||
baseTheme={darkMode ? DARK_THEME : LIGHT_THEME}
|
baseTheme={darkMode ? DARK_THEME : LIGHT_THEME}
|
||||||
theme={
|
theme={euiChartTheme.theme}
|
||||||
darkMode
|
|
||||||
? EUI_CHARTS_THEME_DARK.theme
|
|
||||||
: EUI_CHARTS_THEME_LIGHT.theme
|
|
||||||
}
|
|
||||||
showLegend
|
showLegend
|
||||||
onBrushEnd={onBrushEnd}
|
onBrushEnd={onBrushEnd}
|
||||||
xDomain={{
|
xDomain={{
|
||||||
|
@ -122,6 +124,11 @@ export function PageViewsChart({ data, loading }: Props) {
|
||||||
stackAccessors={['x']}
|
stackAccessors={['x']}
|
||||||
data={data?.items ?? []}
|
data={data?.items ?? []}
|
||||||
name={customSeriesNaming}
|
name={customSeriesNaming}
|
||||||
|
color={
|
||||||
|
!hasBreakdowns
|
||||||
|
? euiChartTheme.theme.colors?.vizColors?.[1]
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Chart>
|
</Chart>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiStat, EuiToolTip } from '@elastic/eui';
|
||||||
import { useFetcher } from '../../../../hooks/useFetcher';
|
import { useFetcher } from '../../../../hooks/useFetcher';
|
||||||
import { I18LABELS } from '../translations';
|
import { I18LABELS } from '../translations';
|
||||||
import { useUxQuery } from '../hooks/useUxQuery';
|
import { useUxQuery } from '../hooks/useUxQuery';
|
||||||
|
import { formatToSec } from '../UXMetrics/KeyUXMetrics';
|
||||||
import { CsmSharedContext } from '../CsmSharedContext';
|
import { CsmSharedContext } from '../CsmSharedContext';
|
||||||
|
|
||||||
const ClFlexGroup = styled(EuiFlexGroup)`
|
const ClFlexGroup = styled(EuiFlexGroup)`
|
||||||
|
@ -49,14 +50,14 @@ export function ClientMetrics() {
|
||||||
|
|
||||||
const STAT_STYLE = { width: '240px' };
|
const STAT_STYLE = { width: '240px' };
|
||||||
|
|
||||||
|
const pageViewsTotal = data?.pageViews?.value ?? 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ClFlexGroup responsive={false}>
|
<ClFlexGroup responsive={false}>
|
||||||
<EuiFlexItem grow={false} style={STAT_STYLE}>
|
<EuiFlexItem grow={false} style={STAT_STYLE}>
|
||||||
<EuiStat
|
<EuiStat
|
||||||
titleSize="l"
|
titleSize="l"
|
||||||
title={
|
title={formatToSec(data?.backEnd?.value ?? 0, 'ms')}
|
||||||
(((data?.backEnd?.value ?? 0) * 1000).toFixed(0) ?? '-') + ' ms'
|
|
||||||
}
|
|
||||||
description={I18LABELS.backEnd}
|
description={I18LABELS.backEnd}
|
||||||
isLoading={status !== 'success'}
|
isLoading={status !== 'success'}
|
||||||
/>
|
/>
|
||||||
|
@ -64,7 +65,7 @@ export function ClientMetrics() {
|
||||||
<EuiFlexItem grow={false} style={STAT_STYLE}>
|
<EuiFlexItem grow={false} style={STAT_STYLE}>
|
||||||
<EuiStat
|
<EuiStat
|
||||||
titleSize="l"
|
titleSize="l"
|
||||||
title={((data?.frontEnd?.value ?? 0)?.toFixed(2) ?? '-') + ' s'}
|
title={formatToSec(data?.frontEnd?.value ?? 0, 'ms')}
|
||||||
description={I18LABELS.frontEnd}
|
description={I18LABELS.frontEnd}
|
||||||
isLoading={status !== 'success'}
|
isLoading={status !== 'success'}
|
||||||
/>
|
/>
|
||||||
|
@ -73,9 +74,13 @@ export function ClientMetrics() {
|
||||||
<EuiStat
|
<EuiStat
|
||||||
titleSize="l"
|
titleSize="l"
|
||||||
title={
|
title={
|
||||||
<EuiToolTip content={data?.pageViews?.value}>
|
pageViewsTotal < 10000 ? (
|
||||||
<>{numeral(data?.pageViews?.value).format('0 a') ?? '-'}</>
|
numeral(pageViewsTotal).format('0,0')
|
||||||
</EuiToolTip>
|
) : (
|
||||||
|
<EuiToolTip content={numeral(pageViewsTotal).format('0,0')}>
|
||||||
|
<>{numeral(pageViewsTotal).format('0 a')}</>
|
||||||
|
</EuiToolTip>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
description={I18LABELS.pageViews}
|
description={I18LABELS.pageViews}
|
||||||
isLoading={status !== 'success'}
|
isLoading={status !== 'success'}
|
||||||
|
|
|
@ -6,8 +6,13 @@
|
||||||
|
|
||||||
import { CurveType, Fit, LineSeries, ScaleType } from '@elastic/charts';
|
import { CurveType, Fit, LineSeries, ScaleType } from '@elastic/charts';
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
|
import {
|
||||||
|
EUI_CHARTS_THEME_DARK,
|
||||||
|
EUI_CHARTS_THEME_LIGHT,
|
||||||
|
} from '@elastic/eui/dist/eui_charts_theme';
|
||||||
import { PercentileRange } from './index';
|
import { PercentileRange } from './index';
|
||||||
import { useBreakdowns } from './use_breakdowns';
|
import { useBreakdowns } from './use_breakdowns';
|
||||||
|
import { useUiSetting$ } from '../../../../../../../../src/plugins/kibana_react/public';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
field: string;
|
field: string;
|
||||||
|
@ -22,6 +27,12 @@ export function BreakdownSeries({
|
||||||
percentileRange,
|
percentileRange,
|
||||||
onLoadingChange,
|
onLoadingChange,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
const [darkMode] = useUiSetting$<boolean>('theme:darkMode');
|
||||||
|
|
||||||
|
const euiChartTheme = darkMode
|
||||||
|
? EUI_CHARTS_THEME_DARK
|
||||||
|
: EUI_CHARTS_THEME_LIGHT;
|
||||||
|
|
||||||
const { data, status } = useBreakdowns({
|
const { data, status } = useBreakdowns({
|
||||||
field,
|
field,
|
||||||
value,
|
value,
|
||||||
|
@ -32,9 +43,11 @@ export function BreakdownSeries({
|
||||||
onLoadingChange(status !== 'success');
|
onLoadingChange(status !== 'success');
|
||||||
}, [status, onLoadingChange]);
|
}, [status, onLoadingChange]);
|
||||||
|
|
||||||
|
// sort index 1 color vizColors1 is already used for overall,
|
||||||
|
// so don't user that here
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{data?.map(({ data: seriesData, name }) => (
|
{data?.map(({ data: seriesData, name }, sortIndex) => (
|
||||||
<LineSeries
|
<LineSeries
|
||||||
id={`${field}-${value}-${name}`}
|
id={`${field}-${value}-${name}`}
|
||||||
key={`${field}-${value}-${name}`}
|
key={`${field}-${value}-${name}`}
|
||||||
|
@ -45,6 +58,11 @@ export function BreakdownSeries({
|
||||||
data={seriesData ?? []}
|
data={seriesData ?? []}
|
||||||
lineSeriesStyle={{ point: { visible: false } }}
|
lineSeriesStyle={{ point: { visible: false } }}
|
||||||
fit={Fit.Linear}
|
fit={Fit.Linear}
|
||||||
|
color={
|
||||||
|
euiChartTheme.theme.colors?.vizColors?.[
|
||||||
|
sortIndex === 0 ? 0 : sortIndex + 1
|
||||||
|
]
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { EuiFlexItem, EuiStat, EuiFlexGroup } from '@elastic/eui';
|
import { EuiFlexItem, EuiStat, EuiFlexGroup } from '@elastic/eui';
|
||||||
|
import numeral from '@elastic/numeral';
|
||||||
import { UXMetrics } from './index';
|
import { UXMetrics } from './index';
|
||||||
import {
|
import {
|
||||||
FCP_LABEL,
|
FCP_LABEL,
|
||||||
|
@ -77,7 +78,7 @@ export function KeyUXMetrics({ data, loading }: Props) {
|
||||||
<EuiFlexItem grow={false} style={STAT_STYLE}>
|
<EuiFlexItem grow={false} style={STAT_STYLE}>
|
||||||
<EuiStat
|
<EuiStat
|
||||||
titleSize="s"
|
titleSize="s"
|
||||||
title={longTaskData?.noOfLongTasks ?? 0}
|
title={numeral(longTaskData?.noOfLongTasks ?? 0).format('0,0')}
|
||||||
description={NO_OF_LONG_TASK}
|
description={NO_OF_LONG_TASK}
|
||||||
isLoading={status !== 'success'}
|
isLoading={status !== 'success'}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -245,10 +245,214 @@ Object {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"minDuration": Object {
|
"loadDistribution": Object {
|
||||||
"min": Object {
|
"percentile_ranks": Object {
|
||||||
"field": "transaction.duration.us",
|
"field": "transaction.duration.us",
|
||||||
"missing": 0,
|
"hdr": Object {
|
||||||
|
"number_of_significant_value_digits": 3,
|
||||||
|
},
|
||||||
|
"keyed": false,
|
||||||
|
"values": Array [
|
||||||
|
0,
|
||||||
|
500000,
|
||||||
|
1000000,
|
||||||
|
1500000,
|
||||||
|
2000000,
|
||||||
|
2500000,
|
||||||
|
3000000,
|
||||||
|
3500000,
|
||||||
|
4000000,
|
||||||
|
4500000,
|
||||||
|
5000000,
|
||||||
|
5500000,
|
||||||
|
6000000,
|
||||||
|
6500000,
|
||||||
|
7000000,
|
||||||
|
7500000,
|
||||||
|
8000000,
|
||||||
|
8500000,
|
||||||
|
9000000,
|
||||||
|
9500000,
|
||||||
|
10000000,
|
||||||
|
10500000,
|
||||||
|
11000000,
|
||||||
|
11500000,
|
||||||
|
12000000,
|
||||||
|
12500000,
|
||||||
|
13000000,
|
||||||
|
13500000,
|
||||||
|
14000000,
|
||||||
|
14500000,
|
||||||
|
15000000,
|
||||||
|
15500000,
|
||||||
|
16000000,
|
||||||
|
16500000,
|
||||||
|
17000000,
|
||||||
|
17500000,
|
||||||
|
18000000,
|
||||||
|
18500000,
|
||||||
|
19000000,
|
||||||
|
19500000,
|
||||||
|
20000000,
|
||||||
|
20500000,
|
||||||
|
21000000,
|
||||||
|
21500000,
|
||||||
|
22000000,
|
||||||
|
22500000,
|
||||||
|
23000000,
|
||||||
|
23500000,
|
||||||
|
24000000,
|
||||||
|
24500000,
|
||||||
|
25000000,
|
||||||
|
25500000,
|
||||||
|
26000000,
|
||||||
|
26500000,
|
||||||
|
27000000,
|
||||||
|
27500000,
|
||||||
|
28000000,
|
||||||
|
28500000,
|
||||||
|
29000000,
|
||||||
|
29500000,
|
||||||
|
30000000,
|
||||||
|
30500000,
|
||||||
|
31000000,
|
||||||
|
31500000,
|
||||||
|
32000000,
|
||||||
|
32500000,
|
||||||
|
33000000,
|
||||||
|
33500000,
|
||||||
|
34000000,
|
||||||
|
34500000,
|
||||||
|
35000000,
|
||||||
|
35500000,
|
||||||
|
36000000,
|
||||||
|
36500000,
|
||||||
|
37000000,
|
||||||
|
37500000,
|
||||||
|
38000000,
|
||||||
|
38500000,
|
||||||
|
39000000,
|
||||||
|
39500000,
|
||||||
|
40000000,
|
||||||
|
40500000,
|
||||||
|
41000000,
|
||||||
|
41500000,
|
||||||
|
42000000,
|
||||||
|
42500000,
|
||||||
|
43000000,
|
||||||
|
43500000,
|
||||||
|
44000000,
|
||||||
|
44500000,
|
||||||
|
45000000,
|
||||||
|
45500000,
|
||||||
|
46000000,
|
||||||
|
46500000,
|
||||||
|
47000000,
|
||||||
|
47500000,
|
||||||
|
48000000,
|
||||||
|
48500000,
|
||||||
|
49000000,
|
||||||
|
49500000,
|
||||||
|
50000000,
|
||||||
|
50500000,
|
||||||
|
51000000,
|
||||||
|
51500000,
|
||||||
|
52000000,
|
||||||
|
52500000,
|
||||||
|
53000000,
|
||||||
|
53500000,
|
||||||
|
54000000,
|
||||||
|
54500000,
|
||||||
|
55000000,
|
||||||
|
55500000,
|
||||||
|
56000000,
|
||||||
|
56500000,
|
||||||
|
57000000,
|
||||||
|
57500000,
|
||||||
|
58000000,
|
||||||
|
58500000,
|
||||||
|
59000000,
|
||||||
|
59500000,
|
||||||
|
60000000,
|
||||||
|
60500000,
|
||||||
|
61000000,
|
||||||
|
61500000,
|
||||||
|
62000000,
|
||||||
|
62500000,
|
||||||
|
63000000,
|
||||||
|
63500000,
|
||||||
|
64000000,
|
||||||
|
64500000,
|
||||||
|
65000000,
|
||||||
|
65500000,
|
||||||
|
66000000,
|
||||||
|
66500000,
|
||||||
|
67000000,
|
||||||
|
67500000,
|
||||||
|
68000000,
|
||||||
|
68500000,
|
||||||
|
69000000,
|
||||||
|
69500000,
|
||||||
|
70000000,
|
||||||
|
70500000,
|
||||||
|
71000000,
|
||||||
|
71500000,
|
||||||
|
72000000,
|
||||||
|
72500000,
|
||||||
|
73000000,
|
||||||
|
73500000,
|
||||||
|
74000000,
|
||||||
|
74500000,
|
||||||
|
75000000,
|
||||||
|
75500000,
|
||||||
|
76000000,
|
||||||
|
76500000,
|
||||||
|
77000000,
|
||||||
|
77500000,
|
||||||
|
78000000,
|
||||||
|
78500000,
|
||||||
|
79000000,
|
||||||
|
79500000,
|
||||||
|
80000000,
|
||||||
|
80500000,
|
||||||
|
81000000,
|
||||||
|
81500000,
|
||||||
|
82000000,
|
||||||
|
82500000,
|
||||||
|
83000000,
|
||||||
|
83500000,
|
||||||
|
84000000,
|
||||||
|
84500000,
|
||||||
|
85000000,
|
||||||
|
85500000,
|
||||||
|
86000000,
|
||||||
|
86500000,
|
||||||
|
87000000,
|
||||||
|
87500000,
|
||||||
|
88000000,
|
||||||
|
88500000,
|
||||||
|
89000000,
|
||||||
|
89500000,
|
||||||
|
90000000,
|
||||||
|
90500000,
|
||||||
|
91000000,
|
||||||
|
91500000,
|
||||||
|
92000000,
|
||||||
|
92500000,
|
||||||
|
93000000,
|
||||||
|
93500000,
|
||||||
|
94000000,
|
||||||
|
94500000,
|
||||||
|
95000000,
|
||||||
|
95500000,
|
||||||
|
96000000,
|
||||||
|
96500000,
|
||||||
|
97000000,
|
||||||
|
97500000,
|
||||||
|
98000000,
|
||||||
|
98500000,
|
||||||
|
99000000,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -72,11 +72,9 @@ export async function getClientMetrics({
|
||||||
// Divide by 1000 to convert ms into seconds
|
// Divide by 1000 to convert ms into seconds
|
||||||
return {
|
return {
|
||||||
pageViews,
|
pageViews,
|
||||||
backEnd: { value: (backEnd.values[pkey] || 0) / 1000 },
|
backEnd: { value: backEnd.values[pkey] || 0 },
|
||||||
frontEnd: {
|
frontEnd: {
|
||||||
value:
|
value: (domInteractive.values[pkey] || 0) - (backEnd.values[pkey] || 0),
|
||||||
((domInteractive.values[pkey] || 0) - (backEnd.values[pkey] || 0)) /
|
|
||||||
1000,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,6 @@ import {
|
||||||
|
|
||||||
export const MICRO_TO_SEC = 1000000;
|
export const MICRO_TO_SEC = 1000000;
|
||||||
|
|
||||||
const NUMBER_OF_PLD_STEPS = 100;
|
|
||||||
|
|
||||||
export function microToSec(val: number) {
|
export function microToSec(val: number) {
|
||||||
return Math.round((val / MICRO_TO_SEC + Number.EPSILON) * 100) / 100;
|
return Math.round((val / MICRO_TO_SEC + Number.EPSILON) * 100) / 100;
|
||||||
}
|
}
|
||||||
|
@ -24,15 +22,31 @@ export function microToSec(val: number) {
|
||||||
export const getPLDChartSteps = ({
|
export const getPLDChartSteps = ({
|
||||||
maxDuration,
|
maxDuration,
|
||||||
minDuration,
|
minDuration,
|
||||||
|
initStepValue,
|
||||||
}: {
|
}: {
|
||||||
maxDuration: number;
|
maxDuration: number;
|
||||||
minDuration: number;
|
minDuration: number;
|
||||||
|
initStepValue?: number;
|
||||||
}) => {
|
}) => {
|
||||||
const stepValue = (maxDuration - minDuration) / NUMBER_OF_PLD_STEPS;
|
let stepValue = 0.5;
|
||||||
const stepValues = [];
|
// if diff is too low, let's lower
|
||||||
for (let i = 1; i < NUMBER_OF_PLD_STEPS + 1; i++) {
|
// down the steps value to increase steps
|
||||||
stepValues.push((stepValue * i + minDuration).toFixed(2));
|
if (maxDuration - minDuration <= 5 * MICRO_TO_SEC) {
|
||||||
|
stepValue = 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (initStepValue) {
|
||||||
|
stepValue = initStepValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let initValue = minDuration;
|
||||||
|
const stepValues = [initValue];
|
||||||
|
|
||||||
|
while (initValue < maxDuration) {
|
||||||
|
initValue += stepValue * MICRO_TO_SEC;
|
||||||
|
stepValues.push(initValue);
|
||||||
|
}
|
||||||
|
|
||||||
return stepValues;
|
return stepValues;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -52,16 +66,21 @@ export async function getPageLoadDistribution({
|
||||||
urlQuery,
|
urlQuery,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// we will first get 100 steps using 0sec and 50sec duration,
|
||||||
|
// most web apps will cover this use case
|
||||||
|
// if 99th percentile is greater than 50sec,
|
||||||
|
// we will fetch additional 5 steps beyond 99th percentile
|
||||||
|
let maxDuration = (maxPercentile ? +maxPercentile : 50) * MICRO_TO_SEC;
|
||||||
|
const minDuration = minPercentile ? +minPercentile * MICRO_TO_SEC : 0;
|
||||||
|
const stepValues = getPLDChartSteps({
|
||||||
|
maxDuration,
|
||||||
|
minDuration,
|
||||||
|
});
|
||||||
|
|
||||||
const params = mergeProjection(projection, {
|
const params = mergeProjection(projection, {
|
||||||
body: {
|
body: {
|
||||||
size: 0,
|
size: 0,
|
||||||
aggs: {
|
aggs: {
|
||||||
minDuration: {
|
|
||||||
min: {
|
|
||||||
field: TRANSACTION_DURATION,
|
|
||||||
missing: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
durPercentiles: {
|
durPercentiles: {
|
||||||
percentiles: {
|
percentiles: {
|
||||||
field: TRANSACTION_DURATION,
|
field: TRANSACTION_DURATION,
|
||||||
|
@ -71,6 +90,16 @@ export async function getPageLoadDistribution({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
loadDistribution: {
|
||||||
|
percentile_ranks: {
|
||||||
|
field: TRANSACTION_DURATION,
|
||||||
|
values: stepValues,
|
||||||
|
keyed: false,
|
||||||
|
hdr: {
|
||||||
|
number_of_significant_value_digits: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -86,22 +115,40 @@ export async function getPageLoadDistribution({
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { durPercentiles, minDuration } = aggregations ?? {};
|
const { durPercentiles, loadDistribution } = aggregations ?? {};
|
||||||
|
|
||||||
const minPerc = minPercentile
|
let pageDistVals = loadDistribution?.values ?? [];
|
||||||
? +minPercentile * MICRO_TO_SEC
|
|
||||||
: minDuration?.value ?? 0;
|
|
||||||
|
|
||||||
const maxPercQuery = durPercentiles?.values['99.0'] ?? 10000;
|
const maxPercQuery = durPercentiles?.values['99.0'] ?? 0;
|
||||||
|
|
||||||
const maxPerc = maxPercentile ? +maxPercentile * MICRO_TO_SEC : maxPercQuery;
|
// we assumed that page load will never exceed 50secs, if 99th percentile is
|
||||||
|
// greater then let's fetch additional 10 steps, to cover that on the chart
|
||||||
|
if (maxPercQuery > maxDuration && !maxPercentile) {
|
||||||
|
const additionalStepsPageVals = await getPercentilesDistribution({
|
||||||
|
setup,
|
||||||
|
maxDuration: maxPercQuery,
|
||||||
|
// we pass 50sec as min to get next steps
|
||||||
|
minDuration: maxDuration,
|
||||||
|
});
|
||||||
|
|
||||||
const pageDist = await getPercentilesDistribution({
|
pageDistVals = pageDistVals.concat(additionalStepsPageVals);
|
||||||
setup,
|
maxDuration = maxPercQuery;
|
||||||
minDuration: minPerc,
|
}
|
||||||
maxDuration: maxPerc,
|
|
||||||
|
// calculate the diff to get actual page load on specific duration value
|
||||||
|
const pageDist = pageDistVals.map(({ key, value }, index: number, arr) => {
|
||||||
|
return {
|
||||||
|
x: microToSec(key),
|
||||||
|
y: index === 0 ? value : value - arr[index - 1].value,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (pageDist.length > 0) {
|
||||||
|
while (pageDist[pageDist.length - 1].y === 0) {
|
||||||
|
pageDist.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Object.entries(durPercentiles?.values ?? {}).forEach(([key, val]) => {
|
Object.entries(durPercentiles?.values ?? {}).forEach(([key, val]) => {
|
||||||
if (durPercentiles?.values?.[key]) {
|
if (durPercentiles?.values?.[key]) {
|
||||||
durPercentiles.values[key] = microToSec(val as number);
|
durPercentiles.values[key] = microToSec(val as number);
|
||||||
|
@ -111,8 +158,8 @@ export async function getPageLoadDistribution({
|
||||||
return {
|
return {
|
||||||
pageLoadDistribution: pageDist,
|
pageLoadDistribution: pageDist,
|
||||||
percentiles: durPercentiles?.values,
|
percentiles: durPercentiles?.values,
|
||||||
minDuration: microToSec(minPerc),
|
minDuration: microToSec(minDuration),
|
||||||
maxDuration: microToSec(maxPerc),
|
maxDuration: microToSec(maxDuration),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +172,11 @@ const getPercentilesDistribution = async ({
|
||||||
minDuration: number;
|
minDuration: number;
|
||||||
maxDuration: number;
|
maxDuration: number;
|
||||||
}) => {
|
}) => {
|
||||||
const stepValues = getPLDChartSteps({ maxDuration, minDuration });
|
const stepValues = getPLDChartSteps({
|
||||||
|
minDuration: minDuration + 0.5 * MICRO_TO_SEC,
|
||||||
|
maxDuration,
|
||||||
|
initStepValue: 0.5,
|
||||||
|
});
|
||||||
|
|
||||||
const projection = getRumPageLoadTransactionsProjection({
|
const projection = getRumPageLoadTransactionsProjection({
|
||||||
setup,
|
setup,
|
||||||
|
@ -153,12 +204,5 @@ const getPercentilesDistribution = async ({
|
||||||
|
|
||||||
const { aggregations } = await apmEventClient.search(params);
|
const { aggregations } = await apmEventClient.search(params);
|
||||||
|
|
||||||
const pageDist = aggregations?.loadDistribution.values ?? [];
|
return aggregations?.loadDistribution.values ?? [];
|
||||||
|
|
||||||
return pageDist.map(({ key, value }, index: number, arr) => {
|
|
||||||
return {
|
|
||||||
x: microToSec(key),
|
|
||||||
y: index === 0 ? value : value - arr[index - 1].value,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,21 +41,21 @@ export const getBreakdownField = (breakdown: string) => {
|
||||||
|
|
||||||
export const getPageLoadDistBreakdown = async ({
|
export const getPageLoadDistBreakdown = async ({
|
||||||
setup,
|
setup,
|
||||||
minDuration,
|
minPercentile,
|
||||||
maxDuration,
|
maxPercentile,
|
||||||
breakdown,
|
breakdown,
|
||||||
urlQuery,
|
urlQuery,
|
||||||
}: {
|
}: {
|
||||||
setup: Setup & SetupTimeRange & SetupUIFilters;
|
setup: Setup & SetupTimeRange & SetupUIFilters;
|
||||||
minDuration: number;
|
minPercentile: number;
|
||||||
maxDuration: number;
|
maxPercentile: number;
|
||||||
breakdown: string;
|
breakdown: string;
|
||||||
urlQuery?: string;
|
urlQuery?: string;
|
||||||
}) => {
|
}) => {
|
||||||
// convert secs to micros
|
// convert secs to micros
|
||||||
const stepValues = getPLDChartSteps({
|
const stepValues = getPLDChartSteps({
|
||||||
minDuration: minDuration * MICRO_TO_SEC,
|
maxDuration: (maxPercentile ? +maxPercentile : 50) * MICRO_TO_SEC,
|
||||||
maxDuration: maxDuration * MICRO_TO_SEC,
|
minDuration: minPercentile ? +minPercentile * MICRO_TO_SEC : 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
const projection = getRumPageLoadTransactionsProjection({
|
const projection = getRumPageLoadTransactionsProjection({
|
||||||
|
|
|
@ -89,8 +89,8 @@ export const rumPageLoadDistBreakdownRoute = createRoute(() => ({
|
||||||
|
|
||||||
return getPageLoadDistBreakdown({
|
return getPageLoadDistBreakdown({
|
||||||
setup,
|
setup,
|
||||||
minDuration: Number(minPercentile),
|
minPercentile: Number(minPercentile),
|
||||||
maxDuration: Number(maxPercentile),
|
maxPercentile: Number(maxPercentile),
|
||||||
breakdown,
|
breakdown,
|
||||||
urlQuery,
|
urlQuery,
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue