Fix GC time calculation (#113992)

Was in µs. Corrected to be in ms.

Also use correct duration formatting on the GC time chart and time spent by dependency chart.
This commit is contained in:
Nathan L Smith 2021-10-12 08:26:05 -05:00 committed by GitHub
parent 4436ed2f71
commit c9e3e0e9b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 317 additions and 169 deletions

View file

@ -27,8 +27,8 @@ import { Annotation } from '../../../../../common/annotations';
import { useChartTheme } from '../../../../../../observability/public';
import {
asAbsoluteDateTime,
asDuration,
asPercent,
getDurationFormatter,
} from '../../../../../common/utils/formatters';
import { Coordinate, TimeSeries } from '../../../../../typings/timeseries';
import { useChartPointerEventContext } from '../../../../context/chart_pointer_event/use_chart_pointer_event_context';
@ -39,6 +39,10 @@ import { ChartContainer } from '../../charts/chart_container';
import { isTimeseriesEmpty, onBrushEnd } from '../../charts/helper/helper';
import { useApmParams } from '../../../../hooks/use_apm_params';
import { useTimeRange } from '../../../../hooks/use_time_range';
import {
getMaxY,
getResponseTimeTickFormatter,
} from '../../../shared/charts/transaction_charts/helper';
interface Props {
fetchStatus: FETCH_STATUS;
@ -50,7 +54,6 @@ interface Props {
}
const asPercentBound = (y: number | null) => asPercent(y, 1);
const asDurationBound = (y: number | null) => asDuration(y);
export function BreakdownChart({
fetchStatus,
@ -82,8 +85,11 @@ export function BreakdownChart({
const isEmpty = isTimeseriesEmpty(timeseries);
const maxY = getMaxY(timeseries);
const yTickFormat: TickFormatter =
yAxisType === 'duration' ? asDurationBound : asPercentBound;
yAxisType === 'duration'
? getResponseTimeTickFormatter(getDurationFormatter(maxY))
: asPercentBound;
return (
<ChartContainer height={height} hasData={!isEmpty} status={fetchStatus}>

View file

@ -9,9 +9,9 @@ import { EuiTitle } from '@elastic/eui';
import React from 'react';
import {
asDecimal,
asDuration,
asInteger,
asPercent,
getDurationFormatter,
getFixedByteFormatter,
} from '../../../../../common/utils/formatters';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
@ -19,22 +19,24 @@ import { GenericMetricsChart } from '../../../../../server/lib/metrics/transform
import { Maybe } from '../../../../../typings/common';
import { FETCH_STATUS } from '../../../../hooks/use_fetcher';
import { TimeseriesChart } from '../timeseries_chart';
import {
getMaxY,
getResponseTimeTickFormatter,
} from '../transaction_charts/helper';
function getYTickFormatter(chart: GenericMetricsChart) {
const max = getMaxY(chart.series);
switch (chart.yUnit) {
case 'bytes': {
const max = Math.max(
...chart.series.map(({ data }) =>
Math.max(...data.map(({ y }) => y || 0))
)
);
return getFixedByteFormatter(max);
}
case 'percent': {
return (y: Maybe<number>) => asPercent(y || 0, 1);
}
case 'time': {
return asDuration;
const durationFormatter = getDurationFormatter(max);
return getResponseTimeTickFormatter(durationFormatter);
}
case 'integer': {
return asInteger;

View file

@ -0,0 +1,133 @@
/*
* 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 {
METRIC_JAVA_GC_COUNT,
METRIC_JAVA_GC_TIME,
} from '../../../../../../common/elasticsearch_fieldnames';
import { Setup } from '../../../../helpers/setup_request';
import { ChartBase } from '../../../types';
import { fetchAndTransformGcMetrics } from './fetch_and_transform_gc_metrics';
describe('fetchAndTransformGcMetrics', () => {
describe('given "jvm.gc.time"', () => {
it('converts the value to milliseconds', async () => {
const chartBase = {} as unknown as ChartBase;
const response = {
hits: { total: { value: 1 } },
aggregations: {
per_pool: {
buckets: [
{
key: 'Copy',
doc_count: 30,
timeseries: {
buckets: [
{
key_as_string: '2021-10-05T16:03:30.000Z',
key: 1633449810000,
doc_count: 1,
max: {
value: 23750,
},
derivative: {
value: 11,
},
value: {
value: 11,
},
},
],
},
},
],
},
},
};
const setup = {
apmEventClient: { search: () => Promise.resolve(response) },
config: { 'xpack.gc.metricsInterval': 0 },
} as unknown as Setup;
const fieldName = METRIC_JAVA_GC_TIME;
const { series } = await fetchAndTransformGcMetrics({
chartBase,
environment: 'test environment',
fieldName,
kuery: '',
operationName: 'test operation name',
setup,
serviceName: 'test service name',
start: 1633456140000,
end: 1633457078105,
});
expect(series[0].data[0].y).toEqual(22000);
});
});
describe('given "jvm.gc.rate"', () => {
it('does not convert the value to milliseconds', async () => {
const chartBase = {} as unknown as ChartBase;
const response = {
hits: {
total: {
value: 62,
},
},
aggregations: {
per_pool: {
buckets: [
{
key: 'Copy',
doc_count: 31,
timeseries: {
buckets: [
{
key_as_string: '2021-10-05T18:01:30.000Z',
key: 1633456890000,
doc_count: 1,
max: {
value: 815,
},
derivative: {
value: 4,
},
value: {
value: 4,
},
},
],
},
},
],
},
},
};
const setup = {
apmEventClient: { search: () => Promise.resolve(response) },
config: { 'xpack.gc.metricsInterval': 0 },
} as unknown as Setup;
const fieldName = METRIC_JAVA_GC_COUNT;
const { series } = await fetchAndTransformGcMetrics({
chartBase,
environment: 'test environment',
fieldName,
kuery: '',
operationName: 'test operation name',
setup,
serviceName: 'test service name',
start: 1633456140000,
end: 1633457078105,
});
expect(series[0].data[0].y).toEqual(8);
});
});
});

View file

@ -135,10 +135,17 @@ export async function fetchAndTransformGcMetrics({
const data = timeseriesData.buckets.map((bucket) => {
// derivative/value will be undefined for the first hit and if the `max` value is null
const bucketValue = bucket.value?.value;
const y = isFiniteNumber(bucketValue)
const unconvertedY = isFiniteNumber(bucketValue)
? round(bucketValue * (60 / bucketSize), 1)
: null;
// convert to milliseconds if we're calculating time, but not for rate
const y =
unconvertedY !== null && fieldName === METRIC_JAVA_GC_TIME
? unconvertedY * 1000
: unconvertedY;
return {
y,
x: bucket.key,

View file

@ -39,11 +39,11 @@ export default function ApiTest({ getService }: FtrProviderContext) {
it('contains CPU usage and System memory usage chart data', async () => {
expect(chartsResponse.status).to.be(200);
expectSnapshot(chartsResponse.body.charts.map((chart) => chart.title)).toMatchInline(`
Array [
"CPU usage",
"System memory usage",
]
`);
Array [
"CPU usage",
"System memory usage",
]
`);
});
describe('CPU usage', () => {
@ -57,25 +57,25 @@ export default function ApiTest({ getService }: FtrProviderContext) {
it('has correct series', () => {
expect(cpuUsageChart).to.not.empty();
expectSnapshot(cpuUsageChart?.series.map(({ title }) => title)).toMatchInline(`
Array [
"System max",
"System average",
"Process max",
"Process average",
]
`);
Array [
"System max",
"System average",
"Process max",
"Process average",
]
`);
});
it('has correct series overall values', () => {
expectSnapshot(cpuUsageChart?.series.map(({ overallValue }) => overallValue))
.toMatchInline(`
Array [
0.714,
0.3877,
0.75,
0.2543,
]
`);
Array [
0.714,
0.3877,
0.75,
0.2543,
]
`);
});
});
@ -91,21 +91,21 @@ export default function ApiTest({ getService }: FtrProviderContext) {
expect(systemMemoryUsageChart).to.not.empty();
expectSnapshot(systemMemoryUsageChart?.series.map(({ title }) => title))
.toMatchInline(`
Array [
"Max",
"Average",
]
`);
Array [
"Max",
"Average",
]
`);
});
it('has correct series overall values', () => {
expectSnapshot(systemMemoryUsageChart?.series.map(({ overallValue }) => overallValue))
.toMatchInline(`
Array [
0.722093920925555,
0.718173546796348,
]
`);
Array [
0.722093920925555,
0.718173546796348,
]
`);
});
});
});
@ -128,16 +128,16 @@ export default function ApiTest({ getService }: FtrProviderContext) {
it('has correct chart data', async () => {
expect(chartsResponse.status).to.be(200);
expectSnapshot(chartsResponse.body.charts.map((chart) => chart.title)).toMatchInline(`
Array [
"CPU usage",
"System memory usage",
"Heap Memory",
"Non-Heap Memory",
"Thread Count",
"Garbage collection per minute",
"Garbage collection time spent per minute",
]
`);
Array [
"CPU usage",
"System memory usage",
"Heap Memory",
"Non-Heap Memory",
"Thread Count",
"Garbage collection per minute",
"Garbage collection time spent per minute",
]
`);
});
describe('CPU usage', () => {
@ -151,37 +151,37 @@ export default function ApiTest({ getService }: FtrProviderContext) {
it('has correct series', () => {
expect(cpuUsageChart).to.not.empty();
expectSnapshot(cpuUsageChart?.series.map(({ title }) => title)).toMatchInline(`
Array [
"System max",
"System average",
"Process max",
"Process average",
]
`);
Array [
"System max",
"System average",
"Process max",
"Process average",
]
`);
});
it('has correct series overall values', () => {
expectSnapshot(cpuUsageChart?.series.map(({ overallValue }) => overallValue))
.toMatchInline(`
Array [
0.203,
0.178777777777778,
0.01,
0.009,
]
`);
Array [
0.203,
0.178777777777778,
0.01,
0.009,
]
`);
});
it('has the correct rate', async () => {
const yValues = cpuUsageChart?.series.map((serie) => first(serie.data)?.y);
expectSnapshot(yValues).toMatchInline(`
Array [
0.193,
0.193,
0.009,
0.009,
]
`);
Array [
0.193,
0.193,
0.009,
0.009,
]
`);
});
});
@ -197,31 +197,31 @@ export default function ApiTest({ getService }: FtrProviderContext) {
expect(systemMemoryUsageChart).to.not.empty();
expectSnapshot(systemMemoryUsageChart?.series.map(({ title }) => title))
.toMatchInline(`
Array [
"Max",
"Average",
]
`);
Array [
"Max",
"Average",
]
`);
});
it('has correct series overall values', () => {
expectSnapshot(systemMemoryUsageChart?.series.map(({ overallValue }) => overallValue))
.toMatchInline(`
Array [
0.707924703557837,
0.705395980841182,
]
`);
Array [
0.707924703557837,
0.705395980841182,
]
`);
});
it('has the correct rate', async () => {
const yValues = systemMemoryUsageChart?.series.map((serie) => first(serie.data)?.y);
expectSnapshot(yValues).toMatchInline(`
Array [
0.707924703557837,
0.707924703557837,
]
`);
Array [
0.707924703557837,
0.707924703557837,
]
`);
});
});
@ -236,34 +236,34 @@ export default function ApiTest({ getService }: FtrProviderContext) {
it('has correct series', () => {
expect(cpuUsageChart).to.not.empty();
expectSnapshot(cpuUsageChart?.series.map(({ title }) => title)).toMatchInline(`
Array [
"Avg. used",
"Avg. committed",
"Avg. limit",
]
`);
Array [
"Avg. used",
"Avg. committed",
"Avg. limit",
]
`);
});
it('has correct series overall values', () => {
expectSnapshot(cpuUsageChart?.series.map(({ overallValue }) => overallValue))
.toMatchInline(`
Array [
222501617.777778,
374341632,
1560281088,
]
`);
Array [
222501617.777778,
374341632,
1560281088,
]
`);
});
it('has the correct rate', async () => {
const yValues = cpuUsageChart?.series.map((serie) => first(serie.data)?.y);
expectSnapshot(yValues).toMatchInline(`
Array [
211472896,
374341632,
1560281088,
]
`);
Array [
211472896,
374341632,
1560281088,
]
`);
});
});
@ -278,31 +278,31 @@ export default function ApiTest({ getService }: FtrProviderContext) {
it('has correct series', () => {
expect(cpuUsageChart).to.not.empty();
expectSnapshot(cpuUsageChart?.series.map(({ title }) => title)).toMatchInline(`
Array [
"Avg. used",
"Avg. committed",
]
`);
Array [
"Avg. used",
"Avg. committed",
]
`);
});
it('has correct series overall values', () => {
expectSnapshot(cpuUsageChart?.series.map(({ overallValue }) => overallValue))
.toMatchInline(`
Array [
138573397.333333,
147677639.111111,
]
`);
Array [
138573397.333333,
147677639.111111,
]
`);
});
it('has the correct rate', async () => {
const yValues = cpuUsageChart?.series.map((serie) => first(serie.data)?.y);
expectSnapshot(yValues).toMatchInline(`
Array [
138162752,
147386368,
]
`);
Array [
138162752,
147386368,
]
`);
});
});
@ -317,31 +317,31 @@ export default function ApiTest({ getService }: FtrProviderContext) {
it('has correct series', () => {
expect(cpuUsageChart).to.not.empty();
expectSnapshot(cpuUsageChart?.series.map(({ title }) => title)).toMatchInline(`
Array [
"Avg. count",
"Max count",
]
`);
Array [
"Avg. count",
"Max count",
]
`);
});
it('has correct series overall values', () => {
expectSnapshot(cpuUsageChart?.series.map(({ overallValue }) => overallValue))
.toMatchInline(`
Array [
44.4444444444444,
45,
]
`);
Array [
44.4444444444444,
45,
]
`);
});
it('has the correct rate', async () => {
const yValues = cpuUsageChart?.series.map((serie) => first(serie.data)?.y);
expectSnapshot(yValues).toMatchInline(`
Array [
44,
44,
]
`);
Array [
44,
44,
]
`);
});
});
@ -356,21 +356,21 @@ export default function ApiTest({ getService }: FtrProviderContext) {
it('has correct series', () => {
expect(cpuUsageChart).to.not.empty();
expectSnapshot(cpuUsageChart?.series.map(({ title }) => title)).toMatchInline(`
Array [
"G1 Old Generation",
"G1 Young Generation",
]
`);
Array [
"G1 Old Generation",
"G1 Young Generation",
]
`);
});
it('has correct series overall values', () => {
expectSnapshot(cpuUsageChart?.series.map(({ overallValue }) => overallValue))
.toMatchInline(`
Array [
0,
3,
]
`);
Array [
0,
3,
]
`);
});
});
@ -385,21 +385,21 @@ export default function ApiTest({ getService }: FtrProviderContext) {
it('has correct series', () => {
expect(cpuUsageChart).to.not.empty();
expectSnapshot(cpuUsageChart?.series.map(({ title }) => title)).toMatchInline(`
Array [
"G1 Old Generation",
"G1 Young Generation",
]
`);
Array [
"G1 Old Generation",
"G1 Young Generation",
]
`);
});
it('has correct series overall values', () => {
expectSnapshot(cpuUsageChart?.series.map(({ overallValue }) => overallValue))
.toMatchInline(`
Array [
0,
37.5,
]
`);
Array [
0,
37500,
]
`);
});
});
});
@ -419,26 +419,26 @@ export default function ApiTest({ getService }: FtrProviderContext) {
expect(systemMemoryUsageChart).to.not.empty();
expectSnapshot(systemMemoryUsageChart?.series.map(({ title }) => title)).toMatchInline(`
Array [
"Max",
"Average",
]
`);
Array [
"Max",
"Average",
]
`);
expectSnapshot(systemMemoryUsageChart?.series.map(({ overallValue }) => overallValue))
.toMatchInline(`
Array [
0.114523896426499,
0.114002376090415,
]
`);
Array [
0.114523896426499,
0.114002376090415,
]
`);
const yValues = systemMemoryUsageChart?.series.map((serie) => first(serie.data)?.y);
expectSnapshot(yValues).toMatchInline(`
Array [
0.11383724014064,
0.11383724014064,
]
`);
Array [
0.11383724014064,
0.11383724014064,
]
`);
});
});
}