[APM] Use rounded bucket sizes for transaction distribution (#42830) (#42978)

* [APM] Use rounded bucket sizes for transaction distribution

* Rename and add examples
This commit is contained in:
Søren Louv-Jansen 2019-08-08 23:31:22 +02:00 committed by GitHub
parent 59c1eb9438
commit aa5d96ff40
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 104 additions and 20 deletions

View file

@ -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();
},

View file

@ -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 { roundToNearestFiveOrTen } from './round_to_nearest_five_or_ten';
describe('roundToNearestFiveOrTen', () => {
[
{
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(roundToNearestFiveOrTen(input)).toBe(output);
});
});
});

View file

@ -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;
}

View file

@ -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<number>('xpack.apm.bucketTargetCount');
const params = {
index: config.get<string>('apm_oss.transactionIndices'),
@ -58,7 +58,7 @@ export function bucketFetcher(
min_doc_count: 0,
extended_bounds: {
min: 0,
max: bucketSize * bucketTargetCount
max: distributionMax
}
},
aggs: {

View file

@ -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
);

View file

@ -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;
}

View file

@ -6,8 +6,20 @@
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 { roundToNearestFiveOrTen } from '../../helpers/round_to_nearest_five_or_ten';
function getBucketSize(max: number, { config }: Setup) {
const minBucketSize: number = config.get<number>(
'xpack.apm.minimumBucketSize'
);
const bucketTargetCount = config.get<number>('xpack.apm.bucketTargetCount');
const bucketSize = max / bucketTargetCount;
return roundToNearestFiveOrTen(
bucketSize > minBucketSize ? bucketSize : minBucketSize
);
}
export type TransactionDistributionAPIResponse = PromiseReturnType<
typeof getTransactionDistribution
@ -27,19 +39,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
);

View file

@ -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]];