Skip to content

Commit

Permalink
[APM] Garbage collection metrics charts
Browse files Browse the repository at this point in the history
Closes #36320.
  • Loading branch information
dgieselaar committed Oct 3, 2019
1 parent 1592600 commit 227b160
Show file tree
Hide file tree
Showing 11 changed files with 297 additions and 7 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions x-pack/legacy/plugins/apm/common/elasticsearch_fieldnames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ export const METRIC_JAVA_NON_HEAP_MEMORY_COMMITTED =
'jvm.memory.non_heap.committed';
export const METRIC_JAVA_NON_HEAP_MEMORY_USED = 'jvm.memory.non_heap.used';
export const METRIC_JAVA_THREAD_COUNT = 'jvm.thread.count';
export const METRIC_JAVA_GC_COUNT = 'jvm.gc.count';
export const METRIC_JAVA_GC_TIME = 'jvm.gc.time';

export const LABELS = 'labels';

export const HOST_NAME = 'host.hostname';
export const CONTAINER_ID = 'container.id';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ export function ServiceNodeMetrics() {
}
}, [serviceName, serviceNodeName]);

const isLoading =
status === FETCH_STATUS.LOADING || status === FETCH_STATUS.PENDING;
const isLoading = status === FETCH_STATUS.LOADING;

return (
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
asDynamicBytes,
asPercent,
getFixedByteFormatter,
asDecimal
asDecimal,
asTime
} from '../../../../utils/formatters';
import { Coordinate } from '../../../../../typings/timeseries';
import { isValidCoordinateValue } from '../../../../utils/isValidCoordinateValue';
Expand Down Expand Up @@ -64,6 +65,9 @@ function getYTickFormatter(chart: GenericMetricsChart) {
case 'percent': {
return (y: number | null | undefined) => asPercent(y || 0, 1);
}
case 'time': {
return (y: number | null | undefined) => asTime(y);
}
default: {
return (y: number | null | undefined) =>
isValidCoordinateValue(y) ? asDecimal(y) : y;
Expand All @@ -79,6 +83,9 @@ function getTooltipFormatter({ yUnit }: GenericMetricsChart) {
case 'percent': {
return (c: Coordinate) => asPercent(c.y || 0, 1);
}
case 'time': {
return (c: Coordinate) => asTime(c.y);
}
default: {
return (c: Coordinate) =>
isValidCoordinateValue(c.y) ? asDecimal(c.y) : c.y;
Expand Down
2 changes: 1 addition & 1 deletion x-pack/legacy/plugins/apm/public/utils/formatters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export function asTime(
value: FormatterValue,
{ withUnit = true, defaultValue = NOT_AVAILABLE_LABEL }: FormatterOptions = {}
) {
if (value == null) {
if (value == null || value === undefined) {
return defaultValue;
}
const formatter = getTimeFormatter(value);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { idx } from '@kbn/elastic-idx';
import theme from '@elastic/eui/dist/eui_theme_light.json';
import { Setup } from '../../../../helpers/setup_request';
import { getMetricsDateHistogramParams } from '../../../../helpers/metrics';
import { ChartBase } from '../../../types';
import { getMetricsProjection } from '../../../../../../common/projections/metrics';
import { mergeProjection } from '../../../../../../common/projections/util/merge_projection';
import {
SERVICE_AGENT_NAME,
LABELS,
METRIC_JAVA_GC_COUNT,
METRIC_JAVA_GC_TIME
} from '../../../../../../common/elasticsearch_fieldnames';

const colors = [
theme.euiColorVis0,
theme.euiColorVis1,
theme.euiColorVis2,
theme.euiColorVis3,
theme.euiColorVis4,
theme.euiColorVis5,
theme.euiColorVis6
];

export async function fetchAndTransformGcMetrics({
setup,
serviceName,
serviceNodeName,
chartBase,
fieldName
}: {
setup: Setup;
serviceName: string;
serviceNodeName?: string;
chartBase: ChartBase;
fieldName: typeof METRIC_JAVA_GC_COUNT | typeof METRIC_JAVA_GC_TIME;
}) {
const { start, end, client } = setup;

const projection = getMetricsProjection({
setup,
serviceName,
serviceNodeName
});

const params = mergeProjection(projection, {
body: {
size: 0,
query: {
bool: {
filter: [
...projection.body.query.bool.filter,
{ exists: { field: fieldName } },
{ term: { [SERVICE_AGENT_NAME]: 'java' } }
]
}
},
aggs: {
per_pool: {
terms: {
field: `${LABELS}.name`
},
aggs: {
average: {
avg: {
field: fieldName
}
},
over_time: {
date_histogram: getMetricsDateHistogramParams(start, end),
aggs: {
max: {
max: {
field: fieldName
}
},
derivative: {
derivative: {
buckets_path: 'max'
}
},
value: {
bucket_script: {
buckets_path: { value: 'derivative' },
script: 'params.value > 0.0 ? params.value : 0.0'
}
}
}
}
}
}
}
}
});

const response = await client.search(params);

const aggregations = idx(response, _ => _.aggregations);

if (!aggregations) {
return {
...chartBase,
totalHits: 0,
series: []
};
}

const series = aggregations.per_pool.buckets.map((poolBucket, i) => {
const label = poolBucket.key;
const timeseriesData = poolBucket.over_time;

const overallValue = poolBucket.average.value;

return {
title: label,
key: label,
type: chartBase.type,
color: colors[i],
overallValue,
data: (idx(timeseriesData, _ => _.buckets) || []).map((bucket, index) => {
if (!('value' in bucket)) {
// derivative/value will be undefined for the first hit
return {
x: bucket.key,
y: 0
};
}

const { value } = bucket.value;
const y = value === null || isNaN(value) ? null : value;
return {
x: bucket.key,
y
};
})
};
});

return {
...chartBase,
totalHits: response.hits.total,
series
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import theme from '@elastic/eui/dist/eui_theme_light.json';
import { i18n } from '@kbn/i18n';
import { METRIC_JAVA_GC_COUNT } from '../../../../../../common/elasticsearch_fieldnames';
import { Setup } from '../../../../helpers/setup_request';
import { fetchAndTransformGcMetrics } from './fetchAndTransformGcMetrics';
import { ChartBase } from '../../../types';

const series = {
[METRIC_JAVA_GC_COUNT]: {
title: i18n.translate('xpack.apm.agentMetrics.java.gcRate', {
defaultMessage: 'GC count'
}),
color: theme.euiColorVis0
}
};

const chartBase: ChartBase = {
title: i18n.translate('xpack.apm.agentMetrics.java.gcCountChartTitle', {
defaultMessage: 'Garbage collection count'
}),
key: 'gc_count_line_chart',
type: 'linemark',
yUnit: 'number',
series
};

const getGcRateChart = (
setup: Setup,
serviceName: string,
serviceNodeName?: string
) => {
return fetchAndTransformGcMetrics({
setup,
serviceName,
serviceNodeName,
chartBase,
fieldName: METRIC_JAVA_GC_COUNT
});
};

export { getGcRateChart };
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import theme from '@elastic/eui/dist/eui_theme_light.json';
import { i18n } from '@kbn/i18n';
import { METRIC_JAVA_GC_TIME } from '../../../../../../common/elasticsearch_fieldnames';
import { Setup } from '../../../../helpers/setup_request';
import { fetchAndTransformGcMetrics } from './fetchAndTransformGcMetrics';
import { ChartBase } from '../../../types';

const series = {
[METRIC_JAVA_GC_TIME]: {
title: i18n.translate('xpack.apm.agentMetrics.java.gcTime', {
defaultMessage: 'GC time'
}),
color: theme.euiColorVis0
}
};

const chartBase: ChartBase = {
title: i18n.translate('xpack.apm.agentMetrics.java.gcTimeChartTitle', {
defaultMessage: 'Garbage collection time'
}),
key: 'gc_time_line_chart',
type: 'linemark',
yUnit: 'time',
series
};

const getGcTimeChart = (
setup: Setup,
serviceName: string,
serviceNodeName?: string
) => {
return fetchAndTransformGcMetrics({
setup,
serviceName,
serviceNodeName,
chartBase,
fieldName: METRIC_JAVA_GC_TIME
});
};

export { getGcTimeChart };
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { getNonHeapMemoryChart } from './non_heap_memory';
import { getThreadCountChart } from './thread_count';
import { getCPUChartData } from '../shared/cpu';
import { getMemoryChartData } from '../shared/memory';
import { getGcRateChart } from './gc/getGcRateChart';
import { getGcTimeChart } from './gc/getGcTimeChart';

export async function getJavaMetricsCharts(
setup: Setup,
Expand All @@ -21,7 +23,9 @@ export async function getJavaMetricsCharts(
getMemoryChartData(setup, serviceName, serviceNodeName),
getHeapMemoryChart(setup, serviceName, serviceNodeName),
getNonHeapMemoryChart(setup, serviceName, serviceNodeName),
getThreadCountChart(setup, serviceName, serviceNodeName)
getThreadCountChart(setup, serviceName, serviceNodeName),
getGcRateChart(setup, serviceName, serviceNodeName),
getGcTimeChart(setup, serviceName, serviceNodeName)
]);

return { charts };
Expand Down
11 changes: 10 additions & 1 deletion x-pack/legacy/plugins/apm/typings/elasticsearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ declare module 'elasticsearch' {
| 'filters'
| 'cardinality'
| 'sampler'
| 'value_count';
| 'value_count'
| 'derivative'
| 'bucket_script';

type AggOptions = AggregationOptionMap & {
[key: string]: any;
Expand Down Expand Up @@ -139,6 +141,13 @@ declare module 'elasticsearch' {
value: number;
};
sampler: SamplerAggregation<AggregationOption[AggregationName]>;
derivative: BucketAggregation<
AggregationOption[AggregationName],
number
>;
bucket_script: {
value: number | null;
};
}[AggregationType & keyof AggregationOption[AggregationName]];
}
>;
Expand Down
Loading

0 comments on commit 227b160

Please sign in to comment.