Skip to content

Commit 13d205a

Browse files
committed
Use stacked chart for page views
1 parent 496152e commit 13d205a

File tree

4 files changed

+184
-30
lines changed

4 files changed

+184
-30
lines changed

x-pack/plugins/apm/public/components/app/RumDashboard/Charts/PageViewsChart.tsx

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,10 @@ export function PageViewsChart({ data, loading }: Props) {
6868
});
6969
};
7070

71-
let breakdownAccessors: Set<string> = new Set();
72-
if (data && data.length > 0) {
73-
data.forEach((item) => {
74-
breakdownAccessors = new Set([
75-
...Array.from(breakdownAccessors),
76-
...Object.keys(item).filter((key) => key !== 'x'),
77-
]);
78-
});
79-
}
71+
const breakdownAccessors =
72+
data?.topItems?.length > 0 ? data?.topItems : ['y'];
73+
74+
const [darkMode] = useUiSetting$<boolean>('theme:darkMode');
8075

8176
const customSeriesNaming: SeriesNameFn = ({ yAccessor }) => {
8277
if (yAccessor === 'y') {
@@ -86,8 +81,6 @@ export function PageViewsChart({ data, loading }: Props) {
8681
return yAccessor;
8782
};
8883

89-
const [darkMode] = useUiSetting$<boolean>('theme:darkMode');
90-
9184
return (
9285
<ChartWrapper loading={loading} height="250px">
9386
{(!loading || data) && (
@@ -115,15 +108,17 @@ export function PageViewsChart({ data, loading }: Props) {
115108
id="page_views"
116109
title={I18LABELS.pageViews}
117110
position={Position.Left}
118-
tickFormat={(d) => numeral(d).format('0a')}
111+
tickFormat={(d) => numeral(d).format('0')}
112+
labelFormat={(d) => numeral(d).format('0a')}
119113
/>
120114
<BarSeries
121115
id={I18LABELS.pageViews}
122116
xScaleType={ScaleType.Time}
123117
yScaleType={ScaleType.Linear}
124118
xAccessor="x"
125119
yAccessors={Array.from(breakdownAccessors)}
126-
data={data ?? []}
120+
stackAccessors={['x']}
121+
data={data?.items ?? []}
127122
name={customSeriesNaming}
128123
/>
129124
</Chart>

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

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,16 @@ export async function getPageViewTrends({
5151
}
5252
: undefined,
5353
},
54+
...(breakdownItem
55+
? {
56+
topBreakdowns: {
57+
terms: {
58+
field: breakdownItem.fieldName,
59+
size: 9,
60+
},
61+
},
62+
}
63+
: {}),
5464
},
5565
},
5666
});
@@ -59,25 +69,44 @@ export async function getPageViewTrends({
5969

6070
const response = await apmEventClient.search(params);
6171

72+
const { topBreakdowns } = response.aggregations ?? {};
73+
74+
// we are only displaying top 9
75+
const topItems: string[] = (topBreakdowns?.buckets ?? []).map(
76+
({ key }) => key as string
77+
);
78+
6279
const result = response.aggregations?.pageViews.buckets ?? [];
6380

64-
return result.map((bucket) => {
65-
const { key: xVal, doc_count: bCount } = bucket;
66-
const res: Record<string, null | number> = {
67-
x: xVal,
68-
y: bCount,
69-
};
70-
if ('breakdown' in bucket) {
71-
const categoryBuckets = bucket.breakdown.buckets;
72-
categoryBuckets.forEach(({ key, doc_count: docCount }) => {
73-
if (key === 'Other') {
74-
res[key + `(${breakdownItem?.name})`] = docCount;
75-
} else {
76-
res[key] = docCount;
81+
return {
82+
topItems,
83+
items: result.map((bucket) => {
84+
const { key: xVal, doc_count: bCount } = bucket;
85+
const res: Record<string, number> = {
86+
x: xVal,
87+
y: bCount,
88+
};
89+
if ('breakdown' in bucket) {
90+
let top9Count = 0;
91+
const categoryBuckets = bucket.breakdown.buckets;
92+
categoryBuckets.forEach(({ key, doc_count: docCount }) => {
93+
if (topItems.includes(key as string)) {
94+
if (res[key]) {
95+
// if term is already in object, just add it to it
96+
res[key] += docCount;
97+
} else {
98+
res[key] = docCount;
99+
}
100+
top9Count += docCount;
101+
}
102+
});
103+
// Top 9 plus others, get a diff from parent bucket total
104+
if (bCount > top9Count) {
105+
res.Other = bCount - top9Count;
77106
}
78-
});
79-
}
107+
}
80108

81-
return res;
82-
});
109+
return res;
110+
}),
111+
};
83112
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
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 expect from '@kbn/expect';
8+
import { expectSnapshot } from '../../../common/match_snapshot';
9+
import { FtrProviderContext } from '../../../common/ftr_provider_context';
10+
11+
export default function rumServicesApiTests({ getService }: FtrProviderContext) {
12+
const supertest = getService('supertest');
13+
const esArchiver = getService('esArchiver');
14+
15+
describe('CSM page views', () => {
16+
describe('when there is no data', () => {
17+
it('returns empty list', async () => {
18+
const response = await supertest.get(
19+
'/api/apm/rum-client/page-view-trends?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-14T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22elastic-co-rum-test%22%5D%7D'
20+
);
21+
22+
expect(response.status).to.be(200);
23+
expect(response.body).to.eql({
24+
cls: '0',
25+
fid: '0.00',
26+
lcp: '0.00',
27+
tbt: '0.00',
28+
fcp: 0,
29+
lcpRanks: [0, 0, 100],
30+
fidRanks: [0, 0, 100],
31+
clsRanks: [0, 0, 100],
32+
});
33+
});
34+
it('returns empty list with breakdowns', async () => {
35+
const response = await supertest.get(
36+
'/api/apm/rum-client/page-view-trends?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-14T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22elastic-co-rum-test%22%5D%7D&breakdowns=%7B%22name%22%3A%22Browser%22%2C%22fieldName%22%3A%22user_agent.name%22%2C%22type%22%3A%22category%22%7D'
37+
);
38+
39+
expect(response.status).to.be(200);
40+
expect(response.body).to.eql({
41+
cls: '0',
42+
fid: '0.00',
43+
lcp: '0.00',
44+
tbt: '0.00',
45+
fcp: 0,
46+
lcpRanks: [0, 0, 100],
47+
fidRanks: [0, 0, 100],
48+
clsRanks: [0, 0, 100],
49+
});
50+
});
51+
});
52+
53+
describe('when there is data', () => {
54+
before(async () => {
55+
await esArchiver.load('8.0.0');
56+
await esArchiver.load('rum_8.0.0');
57+
});
58+
after(async () => {
59+
await esArchiver.unload('8.0.0');
60+
await esArchiver.unload('rum_8.0.0');
61+
});
62+
63+
it('returns page views', async () => {
64+
const response = await supertest.get(
65+
'/api/apm/rum-client/page-view-trends?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-16T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22kibana-frontend-8_0_0%22%5D%7D'
66+
);
67+
68+
expect(response.status).to.be(200);
69+
70+
expectSnapshot(response.body).toMatchInline(`
71+
Object {
72+
"cls": "0.00",
73+
"clsRanks": Array [
74+
100,
75+
0,
76+
0,
77+
],
78+
"fcp": 1072,
79+
"fid": "1.35",
80+
"fidRanks": Array [
81+
0,
82+
0,
83+
100,
84+
],
85+
"lcp": "1.27",
86+
"lcpRanks": Array [
87+
100,
88+
0,
89+
0,
90+
],
91+
"tbt": 0,
92+
}
93+
`);
94+
});
95+
it('returns page views', async () => {
96+
const response = await supertest.get(
97+
'/api/apm/rum-client/page-view-trends?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-16T20%3A35%3A54.654Z&uiFilters=%7B%22serviceName%22%3A%5B%22kibana-frontend-8_0_0%22%5D%7D&breakdowns=%7B%22name%22%3A%22Browser%22%2C%22fieldName%22%3A%22user_agent.name%22%2C%22type%22%3A%22category%22%7D'
98+
);
99+
100+
expect(response.status).to.be(200);
101+
102+
expectSnapshot(response.body).toMatchInline(`
103+
Object {
104+
"cls": "0.00",
105+
"clsRanks": Array [
106+
100,
107+
0,
108+
0,
109+
],
110+
"fcp": 1072,
111+
"fid": "1.35",
112+
"fidRanks": Array [
113+
0,
114+
0,
115+
100,
116+
],
117+
"lcp": "1.27",
118+
"lcpRanks": Array [
119+
100,
120+
0,
121+
0,
122+
],
123+
"tbt": 0,
124+
}
125+
`);
126+
});
127+
});
128+
});
129+
}

x-pack/test/apm_api_integration/trial/tests/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export default function observabilityApiIntegrationTests({ loadTestFile }: FtrPr
3535
loadTestFile(require.resolve('./csm/csm_services.ts'));
3636
loadTestFile(require.resolve('./csm/web_core_vitals.ts'));
3737
loadTestFile(require.resolve('./csm/long_task_metrics.ts'));
38+
loadTestFile(require.resolve('./csm/page_views.ts'));
3839
});
3940
});
4041
}

0 commit comments

Comments
 (0)