From 3178fcf89c190b5e67023c74719ac95dcb89d5d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Wed, 7 Aug 2019 15:13:18 +0200 Subject: [PATCH 1/2] [APM] Use rounded bucket sizes for transaction distribution --- x-pack/legacy/plugins/apm/index.ts | 2 +- .../apm/server/lib/helpers/round_nice.test.ts | 52 +++++++++++++++++++ .../apm/server/lib/helpers/round_nice.ts | 11 ++++ .../distribution/get_buckets/fetcher.ts | 4 +- .../distribution/get_buckets/index.ts | 2 + ...bucket_size.ts => get_distribution_max.ts} | 9 +--- .../lib/transactions/distribution/index.ts | 20 ++++++- .../plugins/apm/typings/elasticsearch.ts | 16 +++--- 8 files changed, 96 insertions(+), 20 deletions(-) create mode 100644 x-pack/legacy/plugins/apm/server/lib/helpers/round_nice.test.ts create mode 100644 x-pack/legacy/plugins/apm/server/lib/helpers/round_nice.ts rename x-pack/legacy/plugins/apm/server/lib/transactions/distribution/{calculate_bucket_size.ts => get_distribution_max.ts} (80%) diff --git a/x-pack/legacy/plugins/apm/index.ts b/x-pack/legacy/plugins/apm/index.ts index d39df608493568..bc12d90eea47f9 100644 --- a/x-pack/legacy/plugins/apm/index.ts +++ b/x-pack/legacy/plugins/apm/index.ts @@ -68,7 +68,7 @@ export const apm: LegacyPluginInitializer = kibana => { // buckets minimumBucketSize: Joi.number().default(15), - bucketTargetCount: Joi.number().default(27) + bucketTargetCount: Joi.number().default(15) }).default(); }, diff --git a/x-pack/legacy/plugins/apm/server/lib/helpers/round_nice.test.ts b/x-pack/legacy/plugins/apm/server/lib/helpers/round_nice.test.ts new file mode 100644 index 00000000000000..056bb3e4852cba --- /dev/null +++ b/x-pack/legacy/plugins/apm/server/lib/helpers/round_nice.test.ts @@ -0,0 +1,52 @@ +/* + * 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 { roundNice } from './round_nice'; + +describe('roundNice', () => { + [ + { + input: 11, + output: 10 + }, + { + input: 45, + output: 50 + }, + { + input: 55, + output: 50 + }, + { + input: 400, + output: 500 + }, + { + input: 1001, + output: 1000 + }, + { + input: 2000, + output: 1000 + }, + { + input: 4000, + output: 5000 + }, + { + input: 20000, + output: 10000 + }, + { + input: 80000, + output: 100000 + } + ].forEach(({ input, output }) => { + it(`should convert ${input} to ${output}`, () => { + expect(roundNice(input)).toBe(output); + }); + }); +}); diff --git a/x-pack/legacy/plugins/apm/server/lib/helpers/round_nice.ts b/x-pack/legacy/plugins/apm/server/lib/helpers/round_nice.ts new file mode 100644 index 00000000000000..e5bcdbf99847c9 --- /dev/null +++ b/x-pack/legacy/plugins/apm/server/lib/helpers/round_nice.ts @@ -0,0 +1,11 @@ +/* + * 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. + */ + +export function roundNice(v: number) { + const five = Math.pow(10, Math.floor(Math.log10(v))) * 5; + const ten = Math.pow(10, Math.round(Math.log10(v))); + return Math.abs(five - v) < Math.abs(ten - v) ? five : ten; +} diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_buckets/fetcher.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_buckets/fetcher.ts index d265aa5173d2f6..458aad225fd941 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_buckets/fetcher.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_buckets/fetcher.ts @@ -23,11 +23,11 @@ export function bucketFetcher( transactionType: string, transactionId: string, traceId: string, + distributionMax: number, bucketSize: number, setup: Setup ) { const { start, end, uiFiltersES, client, config } = setup; - const bucketTargetCount = config.get('xpack.apm.bucketTargetCount'); const params = { index: config.get('apm_oss.transactionIndices'), @@ -58,7 +58,7 @@ export function bucketFetcher( min_doc_count: 0, extended_bounds: { min: 0, - max: bucketSize * bucketTargetCount + max: distributionMax } }, aggs: { diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts index f5cc252fc68f7b..86429986063ed5 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts @@ -14,6 +14,7 @@ export async function getBuckets( transactionType: string, transactionId: string, traceId: string, + distributionMax: number, bucketSize: number, setup: Setup ) { @@ -23,6 +24,7 @@ export async function getBuckets( transactionType, transactionId, traceId, + distributionMax, bucketSize, setup ); diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/calculate_bucket_size.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_distribution_max.ts similarity index 80% rename from x-pack/legacy/plugins/apm/server/lib/transactions/distribution/calculate_bucket_size.ts rename to x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_distribution_max.ts index 20f69a0bd4d8c1..01a186e74ecc79 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/calculate_bucket_size.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/get_distribution_max.ts @@ -13,7 +13,7 @@ import { } from '../../../../common/elasticsearch_fieldnames'; import { Setup } from '../../helpers/setup_request'; -export async function calculateBucketSize( +export async function getDistributionMax( serviceName: string, transactionName: string, transactionType: string, @@ -56,10 +56,5 @@ export async function calculateBucketSize( }; const resp = await client.search(params); - - const minBucketSize: number = config.get('xpack.apm.minimumBucketSize'); - const bucketTargetCount: number = config.get('xpack.apm.bucketTargetCount'); - const max = resp.aggregations.stats.max; - const bucketSize = Math.floor(max / bucketTargetCount); - return bucketSize > minBucketSize ? bucketSize : minBucketSize; + return resp.aggregations.stats.max; } diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/index.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/index.ts index 719b0fb2dd9840..71846cb5502c81 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/index.ts @@ -6,8 +6,18 @@ import { PromiseReturnType } from '../../../../typings/common'; import { Setup } from '../../helpers/setup_request'; -import { calculateBucketSize } from './calculate_bucket_size'; import { getBuckets } from './get_buckets'; +import { getDistributionMax } from './get_distribution_max'; +import { roundNice } from '../../helpers/round_nice'; + +function getBucketSize(max: number, { config }: Setup) { + const minBucketSize: number = config.get( + 'xpack.apm.minimumBucketSize' + ); + const bucketTargetCount = config.get('xpack.apm.bucketTargetCount'); + const bucketSize = max / bucketTargetCount; + return roundNice(bucketSize > minBucketSize ? bucketSize : minBucketSize); +} export type TransactionDistributionAPIResponse = PromiseReturnType< typeof getTransactionDistribution @@ -27,19 +37,25 @@ export async function getTransactionDistribution({ traceId: string; setup: Setup; }) { - const bucketSize = await calculateBucketSize( + const distributionMax = await getDistributionMax( serviceName, transactionName, transactionType, setup ); + if (distributionMax == null) { + return { totalHits: 0, buckets: [], bucketSize: 0 }; + } + + const bucketSize = getBucketSize(distributionMax, setup); const { buckets, totalHits } = await getBuckets( serviceName, transactionName, transactionType, transactionId, traceId, + distributionMax, bucketSize, setup ); diff --git a/x-pack/legacy/plugins/apm/typings/elasticsearch.ts b/x-pack/legacy/plugins/apm/typings/elasticsearch.ts index d8a0ff18ba66be..f424ea21ab34b5 100644 --- a/x-pack/legacy/plugins/apm/typings/elasticsearch.ts +++ b/x-pack/legacy/plugins/apm/typings/elasticsearch.ts @@ -93,16 +93,16 @@ declare module 'elasticsearch' { }; extended_stats: { count: number; - min: number; - max: number; - avg: number; + min: number | null; + max: number | null; + avg: number | null; sum: number; - sum_of_squares: number; - variance: number; - std_deviation: number; + sum_of_squares: number | null; + variance: number | null; + std_deviation: number | null; std_deviation_bounds: { - upper: number; - lower: number; + upper: number | null; + lower: number | null; }; }; }[AggregationType & keyof AggregationOption[AggregationName]]; From 12c235cd4969079eb6454a3aa12822d33b26ae4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Thu, 8 Aug 2019 17:29:57 +0200 Subject: [PATCH 2/2] Rename and add examples --- .../apm/server/lib/helpers/round_nice.ts | 11 ----------- ....ts => round_to_nearest_five_or_ten.test.ts} | 6 +++--- .../lib/helpers/round_to_nearest_five_or_ten.ts | 17 +++++++++++++++++ .../lib/transactions/distribution/index.ts | 6 ++++-- 4 files changed, 24 insertions(+), 16 deletions(-) delete mode 100644 x-pack/legacy/plugins/apm/server/lib/helpers/round_nice.ts rename x-pack/legacy/plugins/apm/server/lib/helpers/{round_nice.test.ts => round_to_nearest_five_or_ten.test.ts} (82%) create mode 100644 x-pack/legacy/plugins/apm/server/lib/helpers/round_to_nearest_five_or_ten.ts diff --git a/x-pack/legacy/plugins/apm/server/lib/helpers/round_nice.ts b/x-pack/legacy/plugins/apm/server/lib/helpers/round_nice.ts deleted file mode 100644 index e5bcdbf99847c9..00000000000000 --- a/x-pack/legacy/plugins/apm/server/lib/helpers/round_nice.ts +++ /dev/null @@ -1,11 +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. - */ - -export function roundNice(v: number) { - const five = Math.pow(10, Math.floor(Math.log10(v))) * 5; - const ten = Math.pow(10, Math.round(Math.log10(v))); - return Math.abs(five - v) < Math.abs(ten - v) ? five : ten; -} diff --git a/x-pack/legacy/plugins/apm/server/lib/helpers/round_nice.test.ts b/x-pack/legacy/plugins/apm/server/lib/helpers/round_to_nearest_five_or_ten.test.ts similarity index 82% rename from x-pack/legacy/plugins/apm/server/lib/helpers/round_nice.test.ts rename to x-pack/legacy/plugins/apm/server/lib/helpers/round_to_nearest_five_or_ten.test.ts index 056bb3e4852cba..0ba08c431844fd 100644 --- a/x-pack/legacy/plugins/apm/server/lib/helpers/round_nice.test.ts +++ b/x-pack/legacy/plugins/apm/server/lib/helpers/round_to_nearest_five_or_ten.test.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { roundNice } from './round_nice'; +import { roundToNearestFiveOrTen } from './round_to_nearest_five_or_ten'; -describe('roundNice', () => { +describe('roundToNearestFiveOrTen', () => { [ { input: 11, @@ -46,7 +46,7 @@ describe('roundNice', () => { } ].forEach(({ input, output }) => { it(`should convert ${input} to ${output}`, () => { - expect(roundNice(input)).toBe(output); + expect(roundToNearestFiveOrTen(input)).toBe(output); }); }); }); diff --git a/x-pack/legacy/plugins/apm/server/lib/helpers/round_to_nearest_five_or_ten.ts b/x-pack/legacy/plugins/apm/server/lib/helpers/round_to_nearest_five_or_ten.ts new file mode 100644 index 00000000000000..7f7a07611c2539 --- /dev/null +++ b/x-pack/legacy/plugins/apm/server/lib/helpers/round_to_nearest_five_or_ten.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +/* + * Examples: + * roundToNearestFiveOrTen(55) -> 50 + * roundToNearestFiveOrTen(95) -> 100 + * roundToNearestFiveOrTen(384) -> 500 + */ +export function roundToNearestFiveOrTen(value: number) { + const five = Math.pow(10, Math.floor(Math.log10(value))) * 5; + const ten = Math.pow(10, Math.round(Math.log10(value))); + return Math.abs(five - value) < Math.abs(ten - value) ? five : ten; +} diff --git a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/index.ts b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/index.ts index 71846cb5502c81..454e247a19cae0 100644 --- a/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/index.ts +++ b/x-pack/legacy/plugins/apm/server/lib/transactions/distribution/index.ts @@ -8,7 +8,7 @@ import { PromiseReturnType } from '../../../../typings/common'; import { Setup } from '../../helpers/setup_request'; import { getBuckets } from './get_buckets'; import { getDistributionMax } from './get_distribution_max'; -import { roundNice } from '../../helpers/round_nice'; +import { roundToNearestFiveOrTen } from '../../helpers/round_to_nearest_five_or_ten'; function getBucketSize(max: number, { config }: Setup) { const minBucketSize: number = config.get( @@ -16,7 +16,9 @@ function getBucketSize(max: number, { config }: Setup) { ); const bucketTargetCount = config.get('xpack.apm.bucketTargetCount'); const bucketSize = max / bucketTargetCount; - return roundNice(bucketSize > minBucketSize ? bucketSize : minBucketSize); + return roundToNearestFiveOrTen( + bucketSize > minBucketSize ? bucketSize : minBucketSize + ); } export type TransactionDistributionAPIResponse = PromiseReturnType<