Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RUM Dashboard] Replace FID with INP #172467

Merged
merged 18 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ export async function getServiceTransactionTypes({
params
);
const transactionTypes =
aggregations?.types.buckets.map((bucket) => bucket.key as string) || [];
aggregations?.types.buckets
.map((bucket) => bucket.key as string)
// we exclude page-exit transactions because they are not relevant for the apm app
// and are only used for the INP values
.filter((value) => value !== 'page-exit') || [];
return { transactionTypes };
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { ReportViewType } from '../../types';
import {
CLS_FIELD,
FCP_FIELD,
FID_FIELD,
INP_FIELD,
LCP_FIELD,
TBT_FIELD,
TRANSACTION_DURATION,
Expand All @@ -31,7 +31,7 @@ import {
ENVIRONMENT_LABEL,
EVENT_DATASET_LABEL,
FCP_LABEL,
FID_LABEL,
INP_LABEL,
HEATMAP_LABEL,
HOST_NAME_LABEL,
KPI_LABEL,
Expand Down Expand Up @@ -102,7 +102,7 @@ export const FieldLabels: Record<string, string> = {
[LCP_FIELD]: LCP_LABEL,
[FCP_FIELD]: FCP_LABEL,
[TBT_FIELD]: TBT_LABEL,
[FID_FIELD]: FID_LABEL,
[INP_FIELD]: INP_LABEL,
[CLS_FIELD]: CLS_LABEL,

[SYNTHETICS_CLS]: CLS_LABEL,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export const FCP_FIELD = 'transaction.marks.agent.firstContentfulPaint';
export const LCP_FIELD = 'transaction.marks.agent.largestContentfulPaint';
export const TBT_FIELD = 'transaction.experience.tbt';
export const FID_FIELD = 'transaction.experience.fid';
export const INP_FIELD = 'numeric_labels.inp_value';
export const CLS_FIELD = 'transaction.experience.cls';

export const PROFILE_ID = 'profile.id';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ export const FID_LABEL = i18n.translate('xpack.exploratoryView.expView.fieldLabe
defaultMessage: 'First input delay',
});

export const INP_LABEL = i18n.translate('xpack.exploratoryView.expView.fieldLabels.inp', {
defaultMessage: 'Interaction to next paint',
});

export const CLS_LABEL = i18n.translate('xpack.exploratoryView.expView.fieldLabels.cls', {
defaultMessage: 'Cumulative layout shift',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ import {
ReportTypes,
USE_BREAK_DOWN_COLUMN,
} from '../constants';
import { buildPhraseFilter } from '../utils';
import { buildPhraseFilter, buildPhrasesFilter } from '../utils';
import {
CLIENT_GEO_COUNTRY_NAME,
CLS_FIELD,
FID_FIELD,
INP_FIELD,
LCP_FIELD,
PROCESSOR_EVENT,
SERVICE_NAME,
Expand All @@ -32,8 +32,9 @@ import {
USER_AGENT_OS_VERSION,
URL_FULL,
SERVICE_ENVIRONMENT,
FID_FIELD,
} from '../constants/elasticsearch_fieldnames';
import { CLS_LABEL, FID_LABEL, LCP_LABEL } from '../constants/labels';
import { CLS_LABEL, FID_LABEL, INP_LABEL, LCP_LABEL } from '../constants/labels';

export function getCoreWebVitalsConfig({ dataView }: ConfigProps): SeriesConfig {
const statusPallete = euiPaletteForStatus(3);
Expand Down Expand Up @@ -87,7 +88,7 @@ export function getCoreWebVitalsConfig({ dataView }: ConfigProps): SeriesConfig
URL_FULL,
],
baseFilters: [
...buildPhraseFilter(TRANSACTION_TYPE, 'page-load', dataView),
...buildPhrasesFilter(TRANSACTION_TYPE, ['page-load', 'page-exit'], dataView),
...buildPhraseFilter(PROCESSOR_EVENT, 'transaction', dataView),
],
labels: { ...FieldLabels, [SERVICE_NAME]: 'Web Application' },
Expand All @@ -113,21 +114,21 @@ export function getCoreWebVitalsConfig({ dataView }: ConfigProps): SeriesConfig
],
},
{
label: FID_LABEL,
id: FID_FIELD,
label: INP_LABEL,
id: INP_FIELD,
columnType: FILTER_RECORDS,
columnFilters: [
{
language: 'kuery',
query: `${FID_FIELD} < 100`,
query: `${INP_FIELD} < 200`,
},
{
language: 'kuery',
query: `${FID_FIELD} > 100 and ${FID_FIELD} < 300`,
query: `${INP_FIELD} > 200 and ${INP_FIELD} < 500`,
},
{
language: 'kuery',
query: `${FID_FIELD} > 300`,
query: `${INP_FIELD} > 500`,
},
],
},
Expand All @@ -150,12 +151,31 @@ export function getCoreWebVitalsConfig({ dataView }: ConfigProps): SeriesConfig
},
],
},
{
label: FID_LABEL,
id: FID_FIELD,
columnType: FILTER_RECORDS,
columnFilters: [
{
language: 'kuery',
query: `${FID_FIELD} < 100`,
},
{
language: 'kuery',
query: `${FID_FIELD} > 100 and ${FID_FIELD} < 300`,
},
{
language: 'kuery',
query: `${FID_FIELD} > 300`,
},
],
},
],
yConfig: [
{ color: statusPallete[0], forAccessor: 'y-axis-column' },
{ color: statusPallete[1], forAccessor: 'y-axis-column-1' },
{ color: statusPallete[2], forAccessor: 'y-axis-column-2' },
],
query: { query: 'transaction.type: "page-load"', language: 'kuery' },
query: { query: 'transaction.type: ("page-load" or "page-exit")', language: 'kuery' },
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
CLIENT_GEO_COUNTRY_NAME,
CLS_FIELD,
FCP_FIELD,
FID_FIELD,
INP_FIELD,
LCP_FIELD,
PROCESSOR_EVENT,
SERVICE_ENVIRONMENT,
Expand All @@ -37,7 +37,7 @@ import {
BACKEND_TIME_LABEL,
CLS_LABEL,
FCP_LABEL,
FID_LABEL,
INP_LABEL,
LCP_LABEL,
PAGE_LOAD_TIME_LABEL,
PAGES_LOADED_LABEL,
Expand Down Expand Up @@ -97,7 +97,7 @@ export function getRumDistributionConfig({ dataView }: ConfigProps): SeriesConfi
{ label: FCP_LABEL, id: FCP_FIELD, field: FCP_FIELD },
{ label: TBT_LABEL, id: TBT_FIELD, field: TBT_FIELD },
{ label: LCP_LABEL, id: LCP_FIELD, field: LCP_FIELD },
{ label: FID_LABEL, id: FID_FIELD, field: FID_FIELD },
{ label: INP_LABEL, id: INP_FIELD, field: INP_FIELD },
{ label: CLS_LABEL, id: CLS_FIELD, field: CLS_FIELD },
],
baseFilters: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,18 @@ export const rumFieldFormats: FieldFormat[] = [
},
},
},
{
field: FID_FIELD,
format: {
id: 'duration',
params: {
inputFormat: 'milliseconds',
outputFormat: 'humanizePrecise',
showSuffix: true,
useShortSuffix: true,
},
},
},
{
field: TRANSACTION_TIME_TO_FIRST_BYTE,
format: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export const sampleAttributeCoreWebVital = {
filter: {
language: 'kuery',
query:
'transaction.type: page-load and processor.event: transaction and transaction.marks.agent.largestContentfulPaint < 2500',
'transaction.type: (page-load or page-exit) and processor.event: transaction and transaction.marks.agent.largestContentfulPaint < 2500',
},
isBucketed: false,
label: 'Good',
Expand All @@ -104,7 +104,7 @@ export const sampleAttributeCoreWebVital = {
query: {
language: 'kuery',
query:
'transaction.type: page-load and processor.event: transaction and transaction.type: "page-load"',
'transaction.type: (page-load or page-exit) and processor.event: transaction and transaction.type: ("page-load" or "page-exit")',
},
visualization: {
axisTitlesVisibilitySettings: {
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/observability/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export {

export type { SloEditLocatorParams } from './locators/slo_edit';

export type { UXMetrics } from './pages/overview/components/sections/ux/core_web_vitals/core_vitals';
export { getCoreVitalsComponent } from './pages/overview/components/sections/ux/core_web_vitals/get_core_web_vitals_lazy';

export { DatePicker } from './pages/overview/components/date_picker/date_picker';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ interface Props {
thresholds: Thresholds;
isCls?: boolean;
helpLabel: string;
dataTestSubj?: string;
}

export function getCoreVitalTooltipMessage(
Expand Down Expand Up @@ -82,6 +83,7 @@ export function CoreVitalItem({
ranks = [100, 0, 0],
isCls,
helpLabel,
dataTestSubj,
}: Props) {
const palette = euiPaletteForStatus(3);

Expand All @@ -96,6 +98,7 @@ export function CoreVitalItem({
return (
<>
<EuiStat
data-test-subj={dataTestSubj}
aria-label={`${title} ${value}`} // aria-label is required when passing a component, instead of a string, as the description
titleSize="s"
title={value ?? ''}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@

import * as React from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
import type { UXMetrics } from '@kbn/observability-shared-plugin/public';
import {
CLS_HELP_LABEL,
CLS_LABEL,
FID_HELP_LABEL,
FID_LABEL,
INP_HELP_LABEL,
INP_LABEL,
LCP_HELP_LABEL,
LCP_LABEL,
} from './translations';
Expand All @@ -28,18 +29,6 @@ export interface CoreVitalProps {
displayTrafficMetric?: boolean;
}

export interface UXMetrics {
cls: number | null;
fid?: number | null;
lcp?: number | null;
tbt: number;
fcp?: number | null;
coreVitalPages: number;
lcpRanks: number[];
fidRanks: number[];
clsRanks: number[];
}

function formatToSec(value?: number | string, fromUnit = 'MicroSec'): string {
const valueInMs = Number(value ?? 0) / (fromUnit === 'MicroSec' ? 1000 : 1);

Expand All @@ -58,7 +47,7 @@ function formatToMilliseconds(value?: number | null) {

const CoreVitalsThresholds = {
LCP: { good: '2.5s', bad: '4.0s' },
FID: { good: '100ms', bad: '300ms' },
INP: { good: '200ms', bad: '500ms' },
CLS: { good: '0.1', bad: '0.25' },
};

Expand All @@ -71,7 +60,7 @@ export default function CoreVitals({
totalPageViews,
displayTrafficMetric = false,
}: CoreVitalProps) {
const { lcp, lcpRanks, fid, fidRanks, cls, clsRanks, coreVitalPages } = data || {};
const { lcp, lcpRanks, inp, inpRanks, cls, clsRanks, coreVitalPages } = data || {};

return (
<>
Expand All @@ -93,16 +82,18 @@ export default function CoreVitals({
loading={loading}
thresholds={CoreVitalsThresholds.LCP}
helpLabel={LCP_HELP_LABEL}
dataTestSubj={'lcp-core-vital'}
/>
</EuiFlexItem>
<EuiFlexItem style={{ flexBasis: 380 }}>
<CoreVitalItem
title={FID_LABEL}
value={formatToMilliseconds(fid)}
ranks={fidRanks}
title={INP_LABEL}
value={formatToMilliseconds(inp)}
ranks={inpRanks}
loading={loading}
thresholds={CoreVitalsThresholds.FID}
helpLabel={FID_HELP_LABEL}
thresholds={CoreVitalsThresholds.INP}
helpLabel={INP_HELP_LABEL}
dataTestSubj={'inp-core-vital'}
/>
</EuiFlexItem>
<EuiFlexItem style={{ flexBasis: 380 }}>
Expand All @@ -114,6 +105,7 @@ export default function CoreVitals({
thresholds={CoreVitalsThresholds.CLS}
isCls={true}
helpLabel={CLS_HELP_LABEL}
dataTestSubj={'cls-core-vital'}
/>
</EuiFlexItem>
</EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export const LCP_LABEL = i18n.translate('xpack.observability.ux.coreVitals.lcp',
defaultMessage: 'Largest contentful paint',
});

export const FID_LABEL = i18n.translate('xpack.observability.ux.coreVitals.fip', {
defaultMessage: 'First input delay',
export const INP_LABEL = i18n.translate('xpack.observability.ux.coreVitals.inp', {
defaultMessage: 'Interaction to Next Paint',
});

export const CLS_LABEL = i18n.translate('xpack.observability.ux.coreVitals.cls', {
Expand Down Expand Up @@ -71,9 +71,9 @@ export const LCP_HELP_LABEL = i18n.translate('xpack.observability.ux.coreVitals.
'Largest contentful paint measures loading performance. To provide a good user experience, LCP should occur within 2.5 seconds of when the page first starts loading.',
});

export const FID_HELP_LABEL = i18n.translate('xpack.observability.ux.coreVitals.fid.help', {
export const INP_HELP_LABEL = i18n.translate('xpack.observability.ux.coreVitals.inp.help', {
defaultMessage:
'First input delay measures interactivity. To provide a good user experience, pages should have a FID of less than 100 milliseconds.',
'INP assesses responsiveness using data from the Event Timing API. When an interaction causes a page to become unresponsive, that is a poor user experience. INP observes the latency of all interactions a user has made with the page, and reports a single value which all (or nearly all) interactions were below. A low INP means the page was consistently able to respond quickly to all—or the vast majority—of user interactions.',
});

export const CLS_HELP_LABEL = i18n.translate('xpack.observability.ux.coreVitals.cls.help', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ export const response: UxFetchDataResponse = {
appLink: '/app/ux',
coreWebVitals: {
cls: 0.01,
fid: 13.5,
lcp: 1942.6666666666667,
tbt: 281.55833333333334,
fcp: 1487,
inp: 285,
coreVitalPages: 100,
lcpRanks: [65, 19, 16],
fidRanks: [73, 11, 16],
inpRanks: [73, 11, 16],
clsRanks: [86, 8, 6],
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe('UXSection', () => {
expect(getByText('elastic-co-frontend')).toBeInTheDocument();
expect(getByText('Largest contentful paint')).toBeInTheDocument();
expect(getByText('1.94 s')).toBeInTheDocument();
expect(getByText('14 ms')).toBeInTheDocument();
expect(getByText('285 ms')).toBeInTheDocument();
expect(getByText('0.010')).toBeInTheDocument();

// LCP Rank Values
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
* 2.0.
*/

import { UXMetrics } from '@kbn/observability-shared-plugin/public';
import type { ObservabilityApp } from '../../../typings/common';
import type { UXMetrics } from '../../pages/overview/components/sections/ux/core_web_vitals/core_vitals';
import { ApmIndicesConfig } from '../../../common/typings';

export interface Stat {
Expand Down
Loading