Skip to content

Commit 322607c

Browse files
[UX] Fixed error rate, made sure all filters are applied (#79222) (#79721)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
1 parent e2ee734 commit 322607c

File tree

6 files changed

+96
-18
lines changed

6 files changed

+96
-18
lines changed

x-pack/plugins/apm/e2e/cypress/integration/csm_dashboard.feature

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ Feature: CSM Dashboard
99
When a user browses the APM UI application for RUM Data
1010
Then should have correct client metrics
1111

12+
Scenario: JS Errors
13+
When a user browses the APM UI application for RUM Data
14+
Then it displays list of relevant js errors
15+
1216
Scenario: Percentile select
1317
When the user changes the selected percentile
1418
Then it displays client metric related to that percentile
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { Then } from 'cypress-cucumber-preprocessor/steps';
8+
import { DEFAULT_TIMEOUT } from './csm_dashboard';
9+
import { getDataTestSubj } from './utils';
10+
11+
Then(`it displays list of relevant js errors`, () => {
12+
cy.get('.euiBasicTable-loading').should('not.be.visible');
13+
cy.get('.euiStat__title-isLoading').should('not.be.visible');
14+
15+
getDataTestSubj('uxJsErrorsTotal').should('have.text', 'Total errors110');
16+
17+
getDataTestSubj('uxJsErrorRate').should(
18+
'have.text',
19+
'Error rate100 %Error rate 100 %'
20+
);
21+
22+
getDataTestSubj('uxJsErrorTable').within(() => {
23+
cy.get('tr.euiTableRow', DEFAULT_TIMEOUT)
24+
.eq(0)
25+
.invoke('text')
26+
.should('eq', 'Error messageTest CaptureErrorImpacted page loads100.0 %');
27+
});
28+
});

x-pack/plugins/apm/public/components/app/RumDashboard/ImpactfulMetrics/JSErrors.tsx

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7-
import React, { useContext, useState } from 'react';
7+
import React, { ReactText, useContext, useState } from 'react';
88
import {
99
EuiBasicTable,
1010
EuiFlexItem,
@@ -16,15 +16,23 @@ import {
1616
} from '@elastic/eui';
1717
import numeral from '@elastic/numeral';
1818
import { i18n } from '@kbn/i18n';
19+
import { FormattedMessage } from '@kbn/i18n/react';
1920
import { useUrlParams } from '../../../../hooks/useUrlParams';
2021
import { useFetcher } from '../../../../hooks/useFetcher';
2122
import { I18LABELS } from '../translations';
2223
import { CsmSharedContext } from '../CsmSharedContext';
24+
import { ErrorDetailLink } from '../../../shared/Links/apm/ErrorDetailLink';
25+
26+
interface JSErrorItem {
27+
errorMessage: string;
28+
errorGroupId: ReactText;
29+
count: number;
30+
}
2331

2432
export function JSErrors() {
2533
const { urlParams, uiFilters } = useUrlParams();
2634

27-
const { start, end, serviceName } = urlParams;
35+
const { start, end, serviceName, searchTerm } = urlParams;
2836

2937
const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 5 });
3038

@@ -37,6 +45,7 @@ export function JSErrors() {
3745
query: {
3846
start,
3947
end,
48+
urlQuery: searchTerm || undefined,
4049
uiFilters: JSON.stringify(uiFilters),
4150
pageSize: String(pagination.pageSize),
4251
pageIndex: String(pagination.pageIndex),
@@ -46,30 +55,39 @@ export function JSErrors() {
4655
}
4756
return Promise.resolve(null);
4857
},
49-
[start, end, serviceName, uiFilters, pagination]
58+
[start, end, serviceName, uiFilters, pagination, searchTerm]
5059
);
5160

5261
const {
5362
sharedData: { totalPageViews },
5463
} = useContext(CsmSharedContext);
5564

56-
const items = (data?.items ?? []).map(({ errorMessage, count }) => ({
57-
errorMessage,
58-
percent: i18n.translate('xpack.apm.rum.jsErrors.percent', {
59-
defaultMessage: '{pageLoadPercent} %',
60-
values: { pageLoadPercent: ((count / totalPageViews) * 100).toFixed(1) },
61-
}),
62-
}));
63-
6465
const cols = [
6566
{
6667
field: 'errorMessage',
6768
name: I18LABELS.errorMessage,
69+
render: (errorMessage: string, item: JSErrorItem) => (
70+
<ErrorDetailLink
71+
serviceName={serviceName!}
72+
errorGroupId={item.errorGroupId as string}
73+
>
74+
{errorMessage}
75+
</ErrorDetailLink>
76+
),
6877
},
6978
{
7079
name: I18LABELS.impactedPageLoads,
71-
field: 'percent',
80+
field: 'count',
7281
align: 'right' as const,
82+
render: (count: number) => (
83+
<FormattedMessage
84+
id="xpack.apm.ux.jsErrors.percent"
85+
defaultMessage="{pageLoadPercent} %"
86+
values={{
87+
pageLoadPercent: ((count / totalPageViews) * 100).toFixed(1),
88+
}}
89+
/>
90+
),
7391
},
7492
];
7593

@@ -89,6 +107,8 @@ export function JSErrors() {
89107
? ((data?.totalErrorPages ?? 0) / totalPageViews) * 100
90108
: 0;
91109

110+
const totalErrors = data?.totalErrors ?? 0;
111+
92112
return (
93113
<>
94114
<EuiTitle size="xs">
@@ -98,18 +118,24 @@ export function JSErrors() {
98118
<EuiFlexGroup>
99119
<EuiFlexItem grow={false}>
100120
<EuiStat
121+
data-test-subj={'uxJsErrorsTotal'}
101122
titleSize="s"
102123
title={
103-
<EuiToolTip content={data?.totalErrors ?? 0}>
104-
<>{numeral(data?.totalErrors ?? 0).format('0 a')}</>
105-
</EuiToolTip>
124+
totalErrors < 1000 ? (
125+
totalErrors
126+
) : (
127+
<EuiToolTip content={totalErrors}>
128+
<>{numeral(totalErrors).format('0 a')}</>
129+
</EuiToolTip>
130+
)
106131
}
107132
description={I18LABELS.totalErrors}
108133
isLoading={status !== 'success'}
109134
/>
110135
</EuiFlexItem>
111136
<EuiFlexItem grow={false}>
112137
<EuiStat
138+
data-test-subj={'uxJsErrorRate'}
113139
titleSize="s"
114140
title={i18n.translate('xpack.apm.rum.jsErrors.errorRateValue', {
115141
defaultMessage: '{errorRate} %',
@@ -124,11 +150,12 @@ export function JSErrors() {
124150
</EuiFlexGroup>
125151
<EuiSpacer size="s" />
126152
<EuiBasicTable
153+
data-test-subj={'uxJsErrorTable'}
127154
loading={status !== 'success'}
128155
responsive={false}
129156
compressed={true}
130157
columns={cols}
131-
items={items}
158+
items={data?.items ?? []}
132159
onChange={onTableChange}
133160
pagination={{
134161
...pagination,

x-pack/plugins/apm/server/lib/rum_client/get_js_errors.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ export async function getJSErrors({
1818
setup,
1919
pageSize,
2020
pageIndex,
21+
urlQuery,
2122
}: {
2223
setup: Setup & SetupTimeRange;
2324
pageSize: number;
2425
pageIndex: number;
26+
urlQuery?: string;
2527
}) {
2628
const projection = getRumErrorsProjection({
2729
setup,
30+
urlQuery,
2831
});
2932

3033
const params = mergeProjection(projection, {
@@ -83,9 +86,10 @@ export async function getJSErrors({
8386
totalErrorPages: totalErrorPages?.value ?? 0,
8487
totalErrors: response.hits.total.value ?? 0,
8588
totalErrorGroups: totalErrorGroups?.value ?? 0,
86-
items: errors?.buckets.map(({ sample, doc_count: count }) => {
89+
items: errors?.buckets.map(({ sample, doc_count: count, key }) => {
8790
return {
8891
count,
92+
errorGroupId: key,
8993
errorMessage: (sample.hits.hits[0]._source as {
9094
error: { exception: Array<{ message: string }> };
9195
}).error.exception?.[0].message,

x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,10 @@ export function getRumPageLoadTransactionsProjection({
6363

6464
export function getRumErrorsProjection({
6565
setup,
66+
urlQuery,
6667
}: {
6768
setup: Setup & SetupTimeRange;
69+
urlQuery?: string;
6870
}) {
6971
const { start, end, esFilter: esFilter } = setup;
7072

@@ -79,6 +81,17 @@ export function getRumErrorsProjection({
7981
},
8082
},
8183
...esFilter,
84+
...(urlQuery
85+
? [
86+
{
87+
wildcard: {
88+
'url.full': {
89+
value: `*${urlQuery}*`,
90+
},
91+
},
92+
},
93+
]
94+
: []),
8295
],
8396
};
8497

x-pack/plugins/apm/server/routes/rum_client.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,17 +211,19 @@ export const rumJSErrors = createRoute(() => ({
211211
uiFiltersRt,
212212
rangeRt,
213213
t.type({ pageSize: t.string, pageIndex: t.string }),
214+
t.partial({ urlQuery: t.string }),
214215
]),
215216
},
216217
handler: async ({ context, request }) => {
217218
const setup = await setupRequest(context, request);
218219

219220
const {
220-
query: { pageSize, pageIndex },
221+
query: { pageSize, pageIndex, urlQuery },
221222
} = context.params;
222223

223224
return getJSErrors({
224225
setup,
226+
urlQuery,
225227
pageSize: Number(pageSize),
226228
pageIndex: Number(pageIndex),
227229
});

0 commit comments

Comments
 (0)