[APM] Remove shared metricsFetcher and minor renames (#29071)

This commit is contained in:
Søren Louv-Jansen 2019-01-23 11:57:20 +01:00 committed by GitHub
parent 37977e3412
commit aac425fe1b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 150 additions and 275 deletions

View file

@ -19,12 +19,12 @@ const ID = 'metricsChartData';
const INITIAL_DATA: MetricsChartAPIResponse = {
memory: {
series: {
averagePercentMemoryUsed: [],
maximumPercentMemoryUsed: []
memoryUsedAvg: [],
memoryUsedMax: []
},
overallValues: {
averagePercentMemoryUsed: null,
maximumPercentMemoryUsed: null
memoryUsedAvg: null,
memoryUsedMax: null
},
totalHits: 0
},

View file

@ -109,13 +109,10 @@ export function getMemorySeries(
defaultMessage: 'System max'
}
),
data: series.maximumPercentMemoryUsed,
data: series.memoryUsedMax,
type: 'linemark',
color: colors.apmBlue,
legendValue: asPercent(
overallValues.maximumPercentMemoryUsed || 0,
1
)
legendValue: asPercent(overallValues.memoryUsedMax || 0, 1)
},
{
title: i18n.translate(
@ -124,13 +121,10 @@ export function getMemorySeries(
defaultMessage: 'System average'
}
),
data: series.averagePercentMemoryUsed,
data: series.memoryUsedAvg,
type: 'linemark',
color: colors.apmGreen,
legendValue: asPercent(
overallValues.averagePercentMemoryUsed || 0,
1
)
legendValue: asPercent(overallValues.memoryUsedAvg || 0, 1)
}
];

View file

@ -1,62 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`APM metrics ES fetcher should fetch metrics with specified aggregations 1`] = `
Array [
Array [
"search",
Object {
"body": Object {
"aggs": Object {
"a": 1,
"b": 2,
"c": 3,
"timeseriesData": Object {
"aggs": Object {},
"date_histogram": Object {
"extended_bounds": Object {
"max": 200,
"min": 100,
},
"field": "@timestamp",
"interval": "1s",
"min_doc_count": 0,
},
},
},
"query": Object {
"bool": Object {
"filter": Array [
Object {
"term": Object {
"context.service.name": "test-service",
},
},
Object {
"term": Object {
"processor.name": "metric",
},
},
Object {
"range": Object {
"@timestamp": Object {
"format": "epoch_millis",
"gte": 100,
"lte": 200,
},
},
},
Object {
"term": Object {
"field": "test.esfilter.query",
},
},
],
},
},
"size": 0,
},
"index": "configurable-apm-metrics-index",
},
],
]
`;

View file

@ -1,30 +0,0 @@
/*
* 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 { getSetupMock } from '../../../testHelpers/mocks';
import { fetchMetrics } from '../metricsFetcher';
describe('APM metrics ES fetcher', () => {
it('should fetch metrics with specified aggregations', () => {
const mockSetup = getSetupMock();
const timeseriesBucketAggregations = {};
const totalAggregations = { a: 1, b: 2, c: 3 };
mockSetup.config.get.mockReturnValue('configurable-apm-metrics-index');
fetchMetrics({
setup: mockSetup,
serviceName: 'test-service',
timeseriesBucketAggregations,
totalAggregations
});
expect(mockSetup.client).toHaveBeenCalledTimes(1);
expect(
mockSetup.client.mock.calls[0][1].body.aggs.timeseriesData.aggs
).toBe(timeseriesBucketAggregations);
expect(mockSetup.client.mock.calls).toMatchSnapshot();
});
});

View file

@ -16,15 +16,15 @@ export interface MetricsChartAPIResponse {
cpu: CPUChartAPIResponse;
}
export async function getAllMetricsChartData(args: MetricsRequestArgs) {
export async function getAllMetricsChartData(
args: MetricsRequestArgs
): Promise<MetricsChartAPIResponse> {
const [memoryChartData, cpuChartData] = await Promise.all([
getMemoryChartData(args),
getCPUChartData(args)
]);
const result: MetricsChartAPIResponse = {
return {
memory: memoryChartData,
cpu: cpuChartData
};
return result;
}

View file

@ -3,12 +3,14 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { AggregationSearchResponse } from 'elasticsearch';
import { AggregationSearchResponse, ESFilter } from 'elasticsearch';
import {
METRIC_PROCESS_CPU_PERCENT,
METRIC_SYSTEM_CPU_PERCENT
METRIC_SYSTEM_CPU_PERCENT,
PROCESSOR_NAME,
SERVICE_NAME
} from 'x-pack/plugins/apm/common/constants';
import { fetchMetrics } from '../metricsFetcher';
import { getBucketSize } from '../../helpers/get_bucket_size';
import { AggValue, MetricsRequestArgs, TimeSeriesBucket } from '../query_types';
interface Bucket extends TimeSeriesBucket {
@ -30,20 +32,51 @@ interface Aggs {
export type ESResponse = AggregationSearchResponse<void, Aggs>;
export async function fetch(args: MetricsRequestArgs) {
return fetchMetrics<Aggs>({
...args,
timeseriesBucketAggregations: {
systemCPUAverage: { avg: { field: METRIC_SYSTEM_CPU_PERCENT } },
systemCPUMax: { max: { field: METRIC_SYSTEM_CPU_PERCENT } },
processCPUAverage: { avg: { field: METRIC_PROCESS_CPU_PERCENT } },
processCPUMax: { max: { field: METRIC_PROCESS_CPU_PERCENT } }
},
totalAggregations: {
systemCPUAverage: { avg: { field: METRIC_SYSTEM_CPU_PERCENT } },
systemCPUMax: { max: { field: METRIC_SYSTEM_CPU_PERCENT } },
processCPUAverage: { avg: { field: METRIC_PROCESS_CPU_PERCENT } },
processCPUMax: { max: { field: METRIC_PROCESS_CPU_PERCENT } }
export async function fetch({
serviceName,
setup
}: MetricsRequestArgs): Promise<ESResponse> {
const { start, end, esFilterQuery, client, config } = setup;
const { intervalString } = getBucketSize(start, end, 'auto');
const filters: ESFilter[] = [
{ term: { [SERVICE_NAME]: serviceName } },
{ term: { [PROCESSOR_NAME]: 'metric' } },
{
range: { '@timestamp': { gte: start, lte: end, format: 'epoch_millis' } }
}
});
];
if (esFilterQuery) {
filters.push(esFilterQuery);
}
const params = {
index: config.get<string>('apm_oss.metricsIndices'),
body: {
size: 0,
query: { bool: { filter: filters } },
aggs: {
timeseriesData: {
date_histogram: {
field: '@timestamp',
interval: intervalString,
min_doc_count: 0,
extended_bounds: { min: start, max: end }
},
aggs: {
systemCPUAverage: { avg: { field: METRIC_SYSTEM_CPU_PERCENT } },
systemCPUMax: { max: { field: METRIC_SYSTEM_CPU_PERCENT } },
processCPUAverage: { avg: { field: METRIC_PROCESS_CPU_PERCENT } },
processCPUMax: { max: { field: METRIC_PROCESS_CPU_PERCENT } }
}
},
systemCPUAverage: { avg: { field: METRIC_SYSTEM_CPU_PERCENT } },
systemCPUMax: { max: { field: METRIC_SYSTEM_CPU_PERCENT } },
processCPUAverage: { avg: { field: METRIC_PROCESS_CPU_PERCENT } },
processCPUMax: { max: { field: METRIC_PROCESS_CPU_PERCENT } }
}
}
};
return client<void, Aggs>('search', params);
}

View file

@ -7,7 +7,7 @@ Array [
Object {
"body": Object {
"aggs": Object {
"averagePercentMemoryUsed": Object {
"memoryUsedAvg": Object {
"avg": Object {
"script": Object {
"lang": "expression",
@ -15,7 +15,7 @@ Array [
},
},
},
"maximumPercentMemoryUsed": Object {
"memoryUsedMax": Object {
"max": Object {
"script": Object {
"lang": "expression",
@ -25,7 +25,7 @@ Array [
},
"timeseriesData": Object {
"aggs": Object {
"averagePercentMemoryUsed": Object {
"memoryUsedAvg": Object {
"avg": Object {
"script": Object {
"lang": "expression",
@ -33,7 +33,7 @@ Array [
},
},
},
"maximumPercentMemoryUsed": Object {
"memoryUsedMax": Object {
"max": Object {
"script": Object {
"lang": "expression",
@ -75,13 +75,6 @@ Array [
},
},
},
Object {
"term": Object {
"field": "test.esfilter.query",
},
},
],
"must": Array [
Object {
"exists": Object {
"field": "system.memory.total",
@ -92,6 +85,11 @@ Array [
"field": "system.memory.actual.free",
},
},
Object {
"term": Object {
"field": "test.esfilter.query",
},
},
],
},
},

View file

@ -3,11 +3,11 @@
exports[`memory chart data transformer should transform ES data 1`] = `
Object {
"overallValues": Object {
"averagePercentMemoryUsed": 300,
"maximumPercentMemoryUsed": 400,
"memoryUsedAvg": 300,
"memoryUsedMax": 400,
},
"series": Object {
"averagePercentMemoryUsed": Array [
"memoryUsedAvg": Array [
Object {
"x": 0,
"y": 0,
@ -49,7 +49,7 @@ Object {
"y": 270,
},
],
"maximumPercentMemoryUsed": Array [
"memoryUsedMax": Array [
Object {
"x": 0,
"y": 0,

View file

@ -16,12 +16,12 @@ describe('memory chart data transformer', () => {
.fill(1)
.map((_, i) => ({
key: i,
maximumPercentMemoryUsed: { value: i * 40 },
averagePercentMemoryUsed: { value: i * 30 }
memoryUsedMax: { value: i * 40 },
memoryUsedAvg: { value: i * 30 }
}))
},
maximumPercentMemoryUsed: { value: 400 },
averagePercentMemoryUsed: { value: 300 }
memoryUsedMax: { value: 400 },
memoryUsedAvg: { value: 300 }
},
hits: { total: 199 }
} as ESResponse;
@ -29,17 +29,14 @@ describe('memory chart data transformer', () => {
const result = transform(response);
expect(result).toMatchSnapshot();
expect(result.series.maximumPercentMemoryUsed).toHaveLength(10);
expect(result.series.averagePercentMemoryUsed).toHaveLength(10);
expect(result.series.memoryUsedMax).toHaveLength(10);
expect(result.series.memoryUsedAvg).toHaveLength(10);
const overall = Object.keys(result.overallValues);
expect(overall).toHaveLength(2);
expect(overall).toEqual(
expect.arrayContaining([
'maximumPercentMemoryUsed',
'averagePercentMemoryUsed'
])
expect.arrayContaining(['memoryUsedMax', 'memoryUsedAvg'])
);
});
});

View file

@ -3,60 +3,79 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { AggregationSearchResponse } from 'elasticsearch';
import { AggregationSearchResponse, ESFilter } from 'elasticsearch';
import {
METRIC_SYSTEM_FREE_MEMORY,
METRIC_SYSTEM_TOTAL_MEMORY
METRIC_SYSTEM_TOTAL_MEMORY,
PROCESSOR_NAME,
SERVICE_NAME
} from 'x-pack/plugins/apm/common/constants';
import { fetchMetrics } from '../metricsFetcher';
import { getBucketSize } from '../../helpers/get_bucket_size';
import { AggValue, MetricsRequestArgs, TimeSeriesBucket } from '../query_types';
interface Bucket extends TimeSeriesBucket {
averagePercentMemoryUsed: AggValue;
maximumPercentMemoryUsed: AggValue;
memoryUsedAvg: AggValue;
memoryUsedMax: AggValue;
}
interface Aggs {
timeseriesData: {
buckets: Bucket[];
};
averagePercentMemoryUsed: AggValue;
maximumPercentMemoryUsed: AggValue;
memoryUsedAvg: AggValue;
memoryUsedMax: AggValue;
}
export type ESResponse = AggregationSearchResponse<void, Aggs>;
const percentSystemMemoryUsedScript = {
script: {
export async function fetch({
serviceName,
setup
}: MetricsRequestArgs): Promise<ESResponse> {
const { start, end, esFilterQuery, client, config } = setup;
const { intervalString } = getBucketSize(start, end, 'auto');
const filters: ESFilter[] = [
{ term: { [SERVICE_NAME]: serviceName } },
{ term: { [PROCESSOR_NAME]: 'metric' } },
{
range: { '@timestamp': { gte: start, lte: end, format: 'epoch_millis' } }
},
{ exists: { field: METRIC_SYSTEM_TOTAL_MEMORY } },
{ exists: { field: METRIC_SYSTEM_FREE_MEMORY } }
];
if (esFilterQuery) {
filters.push(esFilterQuery);
}
const script = {
lang: 'expression',
source: `1 - doc['${METRIC_SYSTEM_FREE_MEMORY}'] / doc['${METRIC_SYSTEM_TOTAL_MEMORY}']`
}
};
};
export async function fetch(args: MetricsRequestArgs) {
return fetchMetrics<Aggs>({
...args,
bool: {
must: [
{
exists: {
field: METRIC_SYSTEM_TOTAL_MEMORY
const params = {
index: config.get<string>('apm_oss.metricsIndices'),
body: {
size: 0,
query: { bool: { filter: filters } },
aggs: {
timeseriesData: {
date_histogram: {
field: '@timestamp',
interval: intervalString,
min_doc_count: 0,
extended_bounds: { min: start, max: end }
},
aggs: {
memoryUsedAvg: { avg: { script } },
memoryUsedMax: { max: { script } }
}
},
{
exists: {
field: METRIC_SYSTEM_FREE_MEMORY
}
}
]
},
timeseriesBucketAggregations: {
averagePercentMemoryUsed: { avg: percentSystemMemoryUsedScript },
maximumPercentMemoryUsed: { max: percentSystemMemoryUsedScript }
},
totalAggregations: {
averagePercentMemoryUsed: { avg: percentSystemMemoryUsedScript },
maximumPercentMemoryUsed: { max: percentSystemMemoryUsedScript }
memoryUsedAvg: { avg: { script } },
memoryUsedMax: { max: { script } }
}
}
});
};
return client<void, Aggs>('search', params);
}

View file

@ -8,37 +8,31 @@ import { ESResponse } from './fetcher';
export interface MemoryChartAPIResponse {
series: {
averagePercentMemoryUsed: Coordinate[];
maximumPercentMemoryUsed: Coordinate[];
memoryUsedAvg: Coordinate[];
memoryUsedMax: Coordinate[];
};
// overall totals for the whole time range
overallValues: {
averagePercentMemoryUsed: number | null;
maximumPercentMemoryUsed: number | null;
memoryUsedAvg: number | null;
memoryUsedMax: number | null;
};
totalHits: number;
}
export type MemoryMetricName =
| 'averagePercentMemoryUsed'
| 'maximumPercentMemoryUsed';
export type MemoryMetricName = 'memoryUsedAvg' | 'memoryUsedMax';
const MEMORY_METRIC_NAMES: MemoryMetricName[] = [
'averagePercentMemoryUsed',
'maximumPercentMemoryUsed'
'memoryUsedAvg',
'memoryUsedMax'
];
export function transform(result: ESResponse): MemoryChartAPIResponse {
const { aggregations, hits } = result;
const {
timeseriesData,
averagePercentMemoryUsed,
maximumPercentMemoryUsed
} = aggregations;
const { timeseriesData, memoryUsedAvg, memoryUsedMax } = aggregations;
const series: MemoryChartAPIResponse['series'] = {
averagePercentMemoryUsed: [],
maximumPercentMemoryUsed: []
memoryUsedAvg: [],
memoryUsedMax: []
};
// using forEach here to avoid looping over the entire dataset
@ -52,8 +46,8 @@ export function transform(result: ESResponse): MemoryChartAPIResponse {
return {
series,
overallValues: {
averagePercentMemoryUsed: averagePercentMemoryUsed.value,
maximumPercentMemoryUsed: maximumPercentMemoryUsed.value
memoryUsedAvg: memoryUsedAvg.value,
memoryUsedMax: memoryUsedMax.value
},
totalHits: hits.total
};

View file

@ -1,65 +0,0 @@
/*
* 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 { ESFilter } from 'elasticsearch';
import { PROCESSOR_NAME, SERVICE_NAME } from '../../../common/constants';
import { getBucketSize } from '../helpers/get_bucket_size';
import { MetricsRequestArgs } from './query_types';
export async function fetchMetrics<T = void>({
serviceName,
setup,
timeseriesBucketAggregations = {},
totalAggregations = {},
bool = {}
}: MetricsRequestArgs) {
const { start, end, esFilterQuery, client, config } = setup;
const { intervalString } = getBucketSize(start, end, 'auto');
const filters: ESFilter[] = [
{ term: { [SERVICE_NAME]: serviceName } },
{
term: {
[PROCESSOR_NAME]: 'metric'
}
},
{
range: {
'@timestamp': { gte: start, lte: end, format: 'epoch_millis' }
}
}
];
if (esFilterQuery) {
filters.push(esFilterQuery);
}
const params = {
index: config.get<string>('apm_oss.metricsIndices'),
body: {
size: 0,
query: {
bool: {
...bool,
filter: filters
}
},
aggs: {
timeseriesData: {
date_histogram: {
field: '@timestamp',
interval: intervalString,
min_doc_count: 0,
extended_bounds: { min: start, max: end }
},
aggs: timeseriesBucketAggregations
},
...totalAggregations
}
}
};
return client<void, T>('search', params);
}

View file

@ -3,15 +3,12 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { StringMap } from 'x-pack/plugins/apm/typings/common';
import { Setup } from '../helpers/setup_request';
export interface MetricsRequestArgs {
serviceName: string;
setup: Setup;
timeseriesBucketAggregations?: StringMap<any>;
totalAggregations?: StringMap<any>;
bool?: StringMap<any>;
}
export interface AggValue {

View file

@ -42,7 +42,7 @@ export async function anomalySeriesFetcher({
intervalString: string;
mlBucketSize: number;
setup: Setup;
}) {
}): Promise<ESResponse | undefined> {
const { client, start, end } = setup;
// move the start back with one bucket size, to ensure to get anomaly data in the beginning