mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[ML] APM Correlations: Fix chart errors caused by inconsistent histogram range steps. (#138259) (#138637)
The `AreaSeries` for the latency correlations charts expect the provided timestamp keys for each series to be the same, otherwise there might be errors in how the chart renders the areas. In some cases this could happen because we fetch the data for the areas independently (for example overall latency and failed transactions latency).
The fix provided by this PR adds optional `durationMin` and `durationMax` parameters to affected endpoints. This way the `durationMin/Max` returned by the first area request (for example "overall latency") can be passed on to the second request to enforce the same buckets/keys (for example for "failed transaction latency").
(cherry picked from commit 3aabd88c16
)
Co-authored-by: Walter Rafelsberger <walter@elastic.co>
This commit is contained in:
parent
bd2c1ee630
commit
fb25009383
13 changed files with 269 additions and 125 deletions
|
@ -168,11 +168,12 @@ describe('useFailedTransactionsCorrelations', () => {
|
|||
);
|
||||
|
||||
try {
|
||||
// Each simulated request takes 100ms. After an inital 50ms
|
||||
// we track the internal requests the hook is running and
|
||||
// check the expected progress after these requests.
|
||||
jest.advanceTimersByTime(50);
|
||||
await waitFor(() => expect(result.current.progress.loaded).toBe(0));
|
||||
jest.advanceTimersByTime(100);
|
||||
await waitFor(() => expect(result.current.progress.loaded).toBe(0));
|
||||
jest.advanceTimersByTime(100);
|
||||
await waitFor(() => expect(result.current.progress.loaded).toBe(0.05));
|
||||
|
||||
expect(result.current.progress).toEqual({
|
||||
|
@ -180,6 +181,28 @@ describe('useFailedTransactionsCorrelations', () => {
|
|||
isRunning: true,
|
||||
loaded: 0.05,
|
||||
});
|
||||
expect(result.current.response).toEqual({
|
||||
ccsWarning: false,
|
||||
fieldStats: undefined,
|
||||
errorHistogram: undefined,
|
||||
failedTransactionsCorrelations: undefined,
|
||||
overallHistogram: [
|
||||
{
|
||||
doc_count: 1234,
|
||||
key: 'the-key',
|
||||
},
|
||||
],
|
||||
percentileThresholdValue: 1.234,
|
||||
});
|
||||
|
||||
jest.advanceTimersByTime(100);
|
||||
await waitFor(() => expect(result.current.progress.loaded).toBe(0.1));
|
||||
|
||||
expect(result.current.progress).toEqual({
|
||||
error: undefined,
|
||||
isRunning: true,
|
||||
loaded: 0.1,
|
||||
});
|
||||
expect(result.current.response).toEqual({
|
||||
ccsWarning: false,
|
||||
fieldStats: undefined,
|
||||
|
@ -200,23 +223,23 @@ describe('useFailedTransactionsCorrelations', () => {
|
|||
});
|
||||
|
||||
jest.advanceTimersByTime(100);
|
||||
await waitFor(() => expect(result.current.progress.loaded).toBe(0.1));
|
||||
await waitFor(() => expect(result.current.progress.loaded).toBe(0.15));
|
||||
|
||||
// field candidates are an implementation detail and
|
||||
// will not be exposed, it will just set loaded to 0.1.
|
||||
// will not be exposed, it will just set loaded to 0.15.
|
||||
expect(result.current.progress).toEqual({
|
||||
error: undefined,
|
||||
isRunning: true,
|
||||
loaded: 0.1,
|
||||
loaded: 0.15,
|
||||
});
|
||||
|
||||
jest.advanceTimersByTime(100);
|
||||
await waitFor(() => expect(result.current.progress.loaded).toBe(1));
|
||||
await waitFor(() => expect(result.current.progress.loaded).toBe(0.9));
|
||||
|
||||
expect(result.current.progress).toEqual({
|
||||
error: undefined,
|
||||
isRunning: true,
|
||||
loaded: 1,
|
||||
loaded: 0.9,
|
||||
});
|
||||
|
||||
expect(result.current.response).toEqual({
|
||||
|
@ -252,9 +275,7 @@ describe('useFailedTransactionsCorrelations', () => {
|
|||
});
|
||||
|
||||
jest.advanceTimersByTime(100);
|
||||
await waitFor(() =>
|
||||
expect(result.current.response.fieldStats).toBeDefined()
|
||||
);
|
||||
await waitFor(() => expect(result.current.progress.loaded).toBe(1));
|
||||
|
||||
expect(result.current.progress).toEqual({
|
||||
error: undefined,
|
||||
|
|
|
@ -37,9 +37,10 @@ import { useFetchParams } from './use_fetch_params';
|
|||
|
||||
// Overall progress is a float from 0 to 1.
|
||||
const LOADED_OVERALL_HISTOGRAM = 0.05;
|
||||
const LOADED_FIELD_CANDIDATES = LOADED_OVERALL_HISTOGRAM + 0.05;
|
||||
const LOADED_ERROR_HISTOGRAM = LOADED_OVERALL_HISTOGRAM + 0.05;
|
||||
const LOADED_FIELD_CANDIDATES = LOADED_ERROR_HISTOGRAM + 0.05;
|
||||
const LOADED_DONE = 1;
|
||||
const PROGRESS_STEP_P_VALUES = 0.9;
|
||||
const PROGRESS_STEP_P_VALUES = 0.9 - LOADED_FIELD_CANDIDATES;
|
||||
|
||||
export function useFailedTransactionsCorrelations() {
|
||||
const fetchParams = useFetchParams();
|
||||
|
@ -85,64 +86,81 @@ export function useFailedTransactionsCorrelations() {
|
|||
fallbackResult: undefined,
|
||||
};
|
||||
|
||||
const [overallHistogramResponse, errorHistogramRespone] =
|
||||
await Promise.all([
|
||||
// Initial call to fetch the overall distribution for the log-log plot.
|
||||
callApmApi(
|
||||
'POST /internal/apm/latency/overall_distribution/transactions',
|
||||
{
|
||||
signal: abortCtrl.current.signal,
|
||||
params: {
|
||||
body: {
|
||||
...fetchParams,
|
||||
percentileThreshold: DEFAULT_PERCENTILE_THRESHOLD,
|
||||
chartType:
|
||||
LatencyDistributionChartType.failedTransactionsCorrelations,
|
||||
},
|
||||
},
|
||||
}
|
||||
),
|
||||
callApmApi(
|
||||
'POST /internal/apm/latency/overall_distribution/transactions',
|
||||
{
|
||||
signal: abortCtrl.current.signal,
|
||||
params: {
|
||||
body: {
|
||||
...fetchParams,
|
||||
percentileThreshold: DEFAULT_PERCENTILE_THRESHOLD,
|
||||
termFilters: [
|
||||
{
|
||||
fieldName: EVENT_OUTCOME,
|
||||
fieldValue: EventOutcome.failure,
|
||||
},
|
||||
],
|
||||
chartType:
|
||||
LatencyDistributionChartType.failedTransactionsCorrelations,
|
||||
},
|
||||
},
|
||||
}
|
||||
),
|
||||
]);
|
||||
|
||||
const { overallHistogram, totalDocCount, percentileThresholdValue } =
|
||||
overallHistogramResponse;
|
||||
const { overallHistogram: errorHistogram } = errorHistogramRespone;
|
||||
|
||||
responseUpdate.errorHistogram = errorHistogram;
|
||||
responseUpdate.overallHistogram = overallHistogram;
|
||||
responseUpdate.totalDocCount = totalDocCount;
|
||||
responseUpdate.percentileThresholdValue = percentileThresholdValue;
|
||||
// Initial call to fetch the overall distribution for the log-log plot.
|
||||
const overallHistogramResponse = await callApmApi(
|
||||
'POST /internal/apm/latency/overall_distribution/transactions',
|
||||
{
|
||||
signal: abortCtrl.current.signal,
|
||||
params: {
|
||||
body: {
|
||||
...fetchParams,
|
||||
percentileThreshold: DEFAULT_PERCENTILE_THRESHOLD,
|
||||
chartType:
|
||||
LatencyDistributionChartType.failedTransactionsCorrelations,
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (abortCtrl.current.signal.aborted) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
overallHistogram,
|
||||
totalDocCount,
|
||||
percentileThresholdValue,
|
||||
durationMin,
|
||||
durationMax,
|
||||
} = overallHistogramResponse;
|
||||
|
||||
responseUpdate.overallHistogram = overallHistogram;
|
||||
responseUpdate.totalDocCount = totalDocCount;
|
||||
responseUpdate.percentileThresholdValue = percentileThresholdValue;
|
||||
|
||||
setResponse({
|
||||
...responseUpdate,
|
||||
loaded: LOADED_OVERALL_HISTOGRAM,
|
||||
});
|
||||
setResponse.flush();
|
||||
|
||||
const errorHistogramResponse = await callApmApi(
|
||||
'POST /internal/apm/latency/overall_distribution/transactions',
|
||||
{
|
||||
signal: abortCtrl.current.signal,
|
||||
params: {
|
||||
body: {
|
||||
...fetchParams,
|
||||
percentileThreshold: DEFAULT_PERCENTILE_THRESHOLD,
|
||||
termFilters: [
|
||||
{
|
||||
fieldName: EVENT_OUTCOME,
|
||||
fieldValue: EventOutcome.failure,
|
||||
},
|
||||
],
|
||||
durationMin,
|
||||
durationMax,
|
||||
chartType:
|
||||
LatencyDistributionChartType.failedTransactionsCorrelations,
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (abortCtrl.current.signal.aborted) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { overallHistogram: errorHistogram } = errorHistogramResponse;
|
||||
|
||||
responseUpdate.errorHistogram = errorHistogram;
|
||||
|
||||
setResponse({
|
||||
...responseUpdate,
|
||||
loaded: LOADED_ERROR_HISTOGRAM,
|
||||
});
|
||||
setResponse.flush();
|
||||
|
||||
const { fieldCandidates: candidates } = await callApmApi(
|
||||
'GET /internal/apm/correlations/field_candidates/transactions',
|
||||
{
|
||||
|
@ -179,7 +197,12 @@ export function useFailedTransactionsCorrelations() {
|
|||
{
|
||||
signal: abortCtrl.current.signal,
|
||||
params: {
|
||||
body: { ...fetchParams, fieldCandidates: fieldCandidatesChunk },
|
||||
body: {
|
||||
...fetchParams,
|
||||
fieldCandidates: fieldCandidatesChunk,
|
||||
durationMin,
|
||||
durationMax,
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
@ -284,7 +307,7 @@ export function useFailedTransactionsCorrelations() {
|
|||
const progress = useMemo(
|
||||
() => ({
|
||||
error,
|
||||
loaded,
|
||||
loaded: Math.round(loaded * 100) / 100,
|
||||
isRunning,
|
||||
}),
|
||||
[error, loaded, isRunning]
|
||||
|
|
|
@ -86,20 +86,25 @@ export function useLatencyCorrelations() {
|
|||
};
|
||||
|
||||
// Initial call to fetch the overall distribution for the log-log plot.
|
||||
const { overallHistogram, totalDocCount, percentileThresholdValue } =
|
||||
await callApmApi(
|
||||
'POST /internal/apm/latency/overall_distribution/transactions',
|
||||
{
|
||||
signal: abortCtrl.current.signal,
|
||||
params: {
|
||||
body: {
|
||||
...fetchParams,
|
||||
percentileThreshold: DEFAULT_PERCENTILE_THRESHOLD,
|
||||
chartType: LatencyDistributionChartType.latencyCorrelations,
|
||||
},
|
||||
const {
|
||||
overallHistogram,
|
||||
totalDocCount,
|
||||
percentileThresholdValue,
|
||||
durationMin,
|
||||
durationMax,
|
||||
} = await callApmApi(
|
||||
'POST /internal/apm/latency/overall_distribution/transactions',
|
||||
{
|
||||
signal: abortCtrl.current.signal,
|
||||
params: {
|
||||
body: {
|
||||
...fetchParams,
|
||||
percentileThreshold: DEFAULT_PERCENTILE_THRESHOLD,
|
||||
chartType: LatencyDistributionChartType.latencyCorrelations,
|
||||
},
|
||||
}
|
||||
);
|
||||
},
|
||||
}
|
||||
);
|
||||
responseUpdate.overallHistogram = overallHistogram;
|
||||
responseUpdate.totalDocCount = totalDocCount;
|
||||
responseUpdate.percentileThresholdValue = percentileThresholdValue;
|
||||
|
@ -192,7 +197,12 @@ export function useLatencyCorrelations() {
|
|||
{
|
||||
signal: abortCtrl.current.signal,
|
||||
params: {
|
||||
body: { ...fetchParams, fieldValuePairs: fieldValuePairChunk },
|
||||
body: {
|
||||
...fetchParams,
|
||||
durationMin,
|
||||
durationMax,
|
||||
fieldValuePairs: fieldValuePairChunk,
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
|
|
@ -86,7 +86,9 @@ export const useTransactionDistributionChartData = () => {
|
|||
params.serviceName &&
|
||||
params.environment &&
|
||||
params.start &&
|
||||
params.end
|
||||
params.end &&
|
||||
overallLatencyData.durationMin &&
|
||||
overallLatencyData.durationMax
|
||||
) {
|
||||
return callApmApi(
|
||||
'POST /internal/apm/latency/overall_distribution/transactions',
|
||||
|
@ -94,6 +96,8 @@ export const useTransactionDistributionChartData = () => {
|
|||
params: {
|
||||
body: {
|
||||
...params,
|
||||
durationMin: overallLatencyData.durationMin,
|
||||
durationMax: overallLatencyData.durationMax,
|
||||
percentileThreshold: DEFAULT_PERCENTILE_THRESHOLD,
|
||||
termFilters: [
|
||||
{
|
||||
|
@ -108,7 +112,7 @@ export const useTransactionDistributionChartData = () => {
|
|||
);
|
||||
}
|
||||
},
|
||||
[params]
|
||||
[params, overallLatencyData.durationMin, overallLatencyData.durationMax]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
|
||||
import type { HistogramItem } from '../../../../../common/correlations/types';
|
||||
|
||||
import { replaceHistogramDotsWithBars } from '.';
|
||||
import { replaceHistogramZerosWithMinimumDomainValue } from '.';
|
||||
|
||||
describe('TransactionDistributionChart', () => {
|
||||
describe('replaceHistogramDotsWithBars', () => {
|
||||
it('does the thing', () => {
|
||||
describe('replaceHistogramZerosWithMinimumDomainValue', () => {
|
||||
it('replaces zeroes', () => {
|
||||
const mockHistogram = [
|
||||
{ doc_count: 10 },
|
||||
{ doc_count: 10 },
|
||||
|
@ -25,7 +25,9 @@ describe('TransactionDistributionChart', () => {
|
|||
{ doc_count: 10 },
|
||||
] as HistogramItem[];
|
||||
|
||||
expect(replaceHistogramDotsWithBars(mockHistogram)).toEqual([
|
||||
expect(
|
||||
replaceHistogramZerosWithMinimumDomainValue(mockHistogram)
|
||||
).toEqual([
|
||||
{ doc_count: 10 },
|
||||
{ doc_count: 10 },
|
||||
{ doc_count: 0.0001 },
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { flatten } from 'lodash';
|
||||
|
||||
import {
|
||||
|
@ -83,18 +83,21 @@ const getAnnotationsStyle = (color = 'gray'): LineAnnotationStyle => ({
|
|||
},
|
||||
});
|
||||
|
||||
// TODO Revisit this approach since it actually manipulates the numbers
|
||||
// showing in the chart and its tooltips.
|
||||
const CHART_PLACEHOLDER_VALUE = 0.0001;
|
||||
// With a log based y axis in combination with the `CURVE_STEP_AFTER` style,
|
||||
// the line of an area would not go down to 0 but end on the y axis at the last value >0.
|
||||
// By replacing the 0s with a small value >0 the line will be drawn as intended.
|
||||
// This is just to visually fix the line, for tooltips, that number will be again rounded down to 0.
|
||||
// Note this workaround is only safe to use for this type of chart because it works with
|
||||
// count based values and not a float based metric for example on the y axis.
|
||||
const Y_AXIS_MIN_DOMAIN = 0.5;
|
||||
const Y_AXIS_MIN_VALUE = 0.0001;
|
||||
|
||||
// Elastic charts will show any lone bin (i.e. a populated bin followed by empty bin)
|
||||
// as a circular marker instead of a bar
|
||||
// This provides a workaround by making the next bin not empty
|
||||
// TODO Find a way to get rid of this workaround since it alters original values of the data.
|
||||
export const replaceHistogramDotsWithBars = (histogramItems: HistogramItem[]) =>
|
||||
export const replaceHistogramZerosWithMinimumDomainValue = (
|
||||
histogramItems: HistogramItem[]
|
||||
) =>
|
||||
histogramItems.reduce((histogramItem, _, i) => {
|
||||
if (histogramItem[i].doc_count === 0) {
|
||||
histogramItem[i].doc_count = CHART_PLACEHOLDER_VALUE;
|
||||
histogramItem[i].doc_count = Y_AXIS_MIN_VALUE;
|
||||
}
|
||||
return histogramItem;
|
||||
}, histogramItems);
|
||||
|
@ -140,9 +143,10 @@ export function DurationDistributionChart({
|
|||
...flatten(data.map((d) => d.histogram)).map((d) => d.doc_count)
|
||||
) ?? 0;
|
||||
const yTicks = Math.max(1, Math.ceil(Math.log10(yMax)));
|
||||
const yAxisMaxDomain = Math.pow(10, yTicks);
|
||||
const yAxisDomain = {
|
||||
min: 0.5,
|
||||
max: Math.pow(10, yTicks),
|
||||
min: Y_AXIS_MIN_DOMAIN,
|
||||
max: yAxisMaxDomain,
|
||||
};
|
||||
|
||||
const selectionAnnotation =
|
||||
|
@ -153,13 +157,22 @@ export function DurationDistributionChart({
|
|||
x0: selection[0],
|
||||
x1: selection[1],
|
||||
y0: 0,
|
||||
y1: 100000,
|
||||
y1: yAxisMaxDomain,
|
||||
},
|
||||
details: 'selection',
|
||||
},
|
||||
]
|
||||
: undefined;
|
||||
|
||||
const chartData = useMemo(
|
||||
() =>
|
||||
data.map((d) => ({
|
||||
...d,
|
||||
histogram: replaceHistogramZerosWithMinimumDomainValue(d.histogram),
|
||||
})),
|
||||
[data]
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
data-test-subj="apmCorrelationsChart"
|
||||
|
@ -178,6 +191,10 @@ export function DurationDistributionChart({
|
|||
line: {
|
||||
visible: true,
|
||||
},
|
||||
point: {
|
||||
visible: false,
|
||||
radius: 0,
|
||||
},
|
||||
},
|
||||
axes: {
|
||||
tickLine: {
|
||||
|
@ -266,26 +283,28 @@ export function DurationDistributionChart({
|
|||
ticks={yTicks}
|
||||
gridLine={{ visible: true }}
|
||||
/>
|
||||
{data.map((d, i) => (
|
||||
{chartData.map((d) => (
|
||||
<AreaSeries
|
||||
key={d.id}
|
||||
id={d.id}
|
||||
xScaleType={ScaleType.Log}
|
||||
yScaleType={ScaleType.Log}
|
||||
data={replaceHistogramDotsWithBars(d.histogram)}
|
||||
data={d.histogram}
|
||||
curve={CurveType.CURVE_STEP_AFTER}
|
||||
xAccessor="key"
|
||||
yAccessors={['doc_count']}
|
||||
color={d.areaSeriesColor}
|
||||
fit="lookahead"
|
||||
// To make the area appear without the orphaned points technique,
|
||||
// we changed the original data to replace values of 0 with 0.0001.
|
||||
fit="linear"
|
||||
areaSeriesStyle={{
|
||||
fit: {
|
||||
line: { visible: true },
|
||||
},
|
||||
}}
|
||||
// To make the area appear with a continuous line,
|
||||
// we changed the original data to replace values of 0 with Y_AXIS_MIN_DOMAIN.
|
||||
// To show the correct values again in tooltips, we use a custom tickFormat to round values.
|
||||
// We can safely do this because all duration values above 0 are without decimal points anyway.
|
||||
// An update for Elastic Charts is in the works to be able to customize the above "fit"
|
||||
// attribute. Once that is available we can get rid of the full workaround.
|
||||
// Elastic Charts issue: https://github.com/elastic/elastic-charts/issues/1489
|
||||
tickFormat={(p) => `${Math.round(p)}`}
|
||||
tickFormat={(p) => `${Math.floor(p)}`}
|
||||
/>
|
||||
))}
|
||||
</Chart>
|
||||
|
|
|
@ -32,14 +32,35 @@ export const fetchDurationHistogramRangeSteps = async ({
|
|||
kuery,
|
||||
query,
|
||||
searchMetrics,
|
||||
durationMinOverride,
|
||||
durationMaxOverride,
|
||||
}: CommonCorrelationsQueryParams & {
|
||||
chartType: LatencyDistributionChartType;
|
||||
setup: Setup;
|
||||
searchMetrics: boolean;
|
||||
}): Promise<number[]> => {
|
||||
durationMinOverride?: number;
|
||||
durationMaxOverride?: number;
|
||||
}): Promise<{
|
||||
durationMin?: number;
|
||||
durationMax?: number;
|
||||
rangeSteps: number[];
|
||||
}> => {
|
||||
const steps = 100;
|
||||
|
||||
if (durationMinOverride && durationMaxOverride) {
|
||||
return {
|
||||
durationMin: durationMinOverride,
|
||||
durationMax: durationMaxOverride,
|
||||
rangeSteps: getHistogramRangeSteps(
|
||||
durationMinOverride,
|
||||
durationMaxOverride,
|
||||
steps
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
const { apmEventClient } = setup;
|
||||
|
||||
const steps = 100;
|
||||
const durationField = getDurationField(chartType, searchMetrics);
|
||||
|
||||
// when using metrics data, ensure we filter by docs with the appropriate duration field
|
||||
|
@ -71,7 +92,7 @@ export const fetchDurationHistogramRangeSteps = async ({
|
|||
);
|
||||
|
||||
if (resp.hits.total.value === 0) {
|
||||
return getHistogramRangeSteps(0, 1, 100);
|
||||
return { rangeSteps: getHistogramRangeSteps(0, 1, 100) };
|
||||
}
|
||||
|
||||
if (
|
||||
|
@ -81,11 +102,15 @@ export const fetchDurationHistogramRangeSteps = async ({
|
|||
isFiniteNumber(resp.aggregations.duration_max.value)
|
||||
)
|
||||
) {
|
||||
return [];
|
||||
return { rangeSteps: [] };
|
||||
}
|
||||
|
||||
const min = resp.aggregations.duration_min.value;
|
||||
const max = resp.aggregations.duration_max.value * 2;
|
||||
const durationMin = resp.aggregations.duration_min.value;
|
||||
const durationMax = resp.aggregations.duration_max.value * 2;
|
||||
|
||||
return getHistogramRangeSteps(min, max, steps);
|
||||
return {
|
||||
durationMin,
|
||||
durationMax,
|
||||
rangeSteps: getHistogramRangeSteps(durationMin, durationMax, steps),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -22,16 +22,20 @@ export const fetchPValues = async ({
|
|||
environment,
|
||||
kuery,
|
||||
query,
|
||||
durationMin,
|
||||
durationMax,
|
||||
fieldCandidates,
|
||||
}: CommonCorrelationsQueryParams & {
|
||||
setup: Setup;
|
||||
durationMin?: number;
|
||||
durationMax?: number;
|
||||
fieldCandidates: string[];
|
||||
}) => {
|
||||
const chartType = LatencyDistributionChartType.failedTransactionsCorrelations;
|
||||
const searchMetrics = false; // failed transactions correlations does not search metrics documents
|
||||
const eventType = getEventType(chartType, searchMetrics);
|
||||
|
||||
const rangeSteps = await fetchDurationHistogramRangeSteps({
|
||||
const { rangeSteps } = await fetchDurationHistogramRangeSteps({
|
||||
setup,
|
||||
chartType,
|
||||
start,
|
||||
|
@ -40,6 +44,8 @@ export const fetchPValues = async ({
|
|||
kuery,
|
||||
query,
|
||||
searchMetrics,
|
||||
durationMinOverride: durationMin,
|
||||
durationMaxOverride: durationMax,
|
||||
});
|
||||
|
||||
const { fulfilled, rejected } = splitAllSettledPromises(
|
||||
|
|
|
@ -34,9 +34,13 @@ export const fetchSignificantCorrelations = async ({
|
|||
environment,
|
||||
kuery,
|
||||
query,
|
||||
durationMinOverride,
|
||||
durationMaxOverride,
|
||||
fieldValuePairs,
|
||||
}: CommonCorrelationsQueryParams & {
|
||||
setup: Setup;
|
||||
durationMinOverride?: number;
|
||||
durationMaxOverride?: number;
|
||||
fieldValuePairs: FieldValuePair[];
|
||||
}) => {
|
||||
// Create an array of ranges [2, 4, 6, ..., 98]
|
||||
|
@ -75,7 +79,7 @@ export const fetchSignificantCorrelations = async ({
|
|||
ranges,
|
||||
});
|
||||
|
||||
const histogramRangeSteps = await fetchDurationHistogramRangeSteps({
|
||||
const { rangeSteps } = await fetchDurationHistogramRangeSteps({
|
||||
setup,
|
||||
chartType,
|
||||
start,
|
||||
|
@ -84,6 +88,8 @@ export const fetchSignificantCorrelations = async ({
|
|||
kuery,
|
||||
query,
|
||||
searchMetrics,
|
||||
durationMinOverride,
|
||||
durationMaxOverride,
|
||||
});
|
||||
|
||||
const { fulfilled, rejected } = splitAllSettledPromises(
|
||||
|
@ -100,7 +106,7 @@ export const fetchSignificantCorrelations = async ({
|
|||
expectations,
|
||||
ranges,
|
||||
fractions,
|
||||
histogramRangeSteps,
|
||||
histogramRangeSteps: rangeSteps,
|
||||
totalDocCount,
|
||||
fieldValuePair,
|
||||
})
|
||||
|
@ -147,7 +153,7 @@ export const fetchSignificantCorrelations = async ({
|
|||
filter: [query, ...termQuery(fieldName, fieldValue)],
|
||||
},
|
||||
},
|
||||
rangeSteps: histogramRangeSteps,
|
||||
rangeSteps,
|
||||
searchMetrics,
|
||||
});
|
||||
|
||||
|
|
|
@ -307,6 +307,8 @@ const significantCorrelationsTransactionsRoute = createApmServerRoute({
|
|||
serviceName: t.string,
|
||||
transactionName: t.string,
|
||||
transactionType: t.string,
|
||||
durationMin: toNumberRt,
|
||||
durationMax: toNumberRt,
|
||||
}),
|
||||
environmentRt,
|
||||
kueryRt,
|
||||
|
@ -343,6 +345,8 @@ const significantCorrelationsTransactionsRoute = createApmServerRoute({
|
|||
end,
|
||||
environment,
|
||||
kuery,
|
||||
durationMin,
|
||||
durationMax,
|
||||
fieldValuePairs,
|
||||
},
|
||||
} = resources.params;
|
||||
|
@ -362,6 +366,8 @@ const significantCorrelationsTransactionsRoute = createApmServerRoute({
|
|||
],
|
||||
},
|
||||
},
|
||||
durationMinOverride: durationMin,
|
||||
durationMaxOverride: durationMax,
|
||||
fieldValuePairs,
|
||||
});
|
||||
},
|
||||
|
@ -375,6 +381,8 @@ const pValuesTransactionsRoute = createApmServerRoute({
|
|||
serviceName: t.string,
|
||||
transactionName: t.string,
|
||||
transactionType: t.string,
|
||||
durationMin: toNumberRt,
|
||||
durationMax: toNumberRt,
|
||||
}),
|
||||
environmentRt,
|
||||
kueryRt,
|
||||
|
@ -405,6 +413,8 @@ const pValuesTransactionsRoute = createApmServerRoute({
|
|||
end,
|
||||
environment,
|
||||
kuery,
|
||||
durationMin,
|
||||
durationMax,
|
||||
fieldCandidates,
|
||||
},
|
||||
} = resources.params;
|
||||
|
@ -424,6 +434,8 @@ const pValuesTransactionsRoute = createApmServerRoute({
|
|||
],
|
||||
},
|
||||
},
|
||||
durationMin,
|
||||
durationMax,
|
||||
fieldCandidates,
|
||||
});
|
||||
},
|
||||
|
|
|
@ -28,6 +28,8 @@ export async function getOverallLatencyDistribution({
|
|||
kuery,
|
||||
query,
|
||||
percentileThreshold,
|
||||
durationMinOverride,
|
||||
durationMaxOverride,
|
||||
searchMetrics,
|
||||
}: {
|
||||
chartType: LatencyDistributionChartType;
|
||||
|
@ -38,6 +40,8 @@ export async function getOverallLatencyDistribution({
|
|||
kuery: string;
|
||||
query: estypes.QueryDslQueryContainer;
|
||||
percentileThreshold: number;
|
||||
durationMinOverride?: number;
|
||||
durationMaxOverride?: number;
|
||||
searchMetrics: boolean;
|
||||
}) {
|
||||
return withApmSpan('get_overall_latency_distribution', async () => {
|
||||
|
@ -63,23 +67,25 @@ export async function getOverallLatencyDistribution({
|
|||
}
|
||||
|
||||
// #2: get histogram range steps
|
||||
const rangeSteps = await fetchDurationHistogramRangeSteps({
|
||||
chartType,
|
||||
setup,
|
||||
start,
|
||||
end,
|
||||
environment,
|
||||
kuery,
|
||||
query,
|
||||
searchMetrics,
|
||||
});
|
||||
const { durationMin, durationMax, rangeSteps } =
|
||||
await fetchDurationHistogramRangeSteps({
|
||||
chartType,
|
||||
setup,
|
||||
start,
|
||||
end,
|
||||
environment,
|
||||
kuery,
|
||||
query,
|
||||
searchMetrics,
|
||||
durationMinOverride,
|
||||
durationMaxOverride,
|
||||
});
|
||||
|
||||
if (!rangeSteps) {
|
||||
return overallLatencyDistribution;
|
||||
}
|
||||
|
||||
// #3: get histogram chart data
|
||||
|
||||
const { totalDocCount, durationRanges } = await fetchDurationRanges({
|
||||
chartType,
|
||||
setup,
|
||||
|
@ -92,6 +98,8 @@ export async function getOverallLatencyDistribution({
|
|||
searchMetrics,
|
||||
});
|
||||
|
||||
overallLatencyDistribution.durationMin = durationMin;
|
||||
overallLatencyDistribution.durationMax = durationMax;
|
||||
overallLatencyDistribution.totalDocCount = totalDocCount;
|
||||
overallLatencyDistribution.overallHistogram = durationRanges;
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ const latencyOverallTransactionDistributionRoute = createApmServerRoute({
|
|||
fieldValue: t.union([t.string, toNumberRt]),
|
||||
})
|
||||
),
|
||||
durationMin: toNumberRt,
|
||||
durationMax: toNumberRt,
|
||||
}),
|
||||
environmentRt,
|
||||
kueryRt,
|
||||
|
@ -63,6 +65,8 @@ const latencyOverallTransactionDistributionRoute = createApmServerRoute({
|
|||
start,
|
||||
end,
|
||||
percentileThreshold,
|
||||
durationMin,
|
||||
durationMax,
|
||||
termFilters,
|
||||
chartType,
|
||||
} = resources.params.body;
|
||||
|
@ -99,6 +103,8 @@ const latencyOverallTransactionDistributionRoute = createApmServerRoute({
|
|||
},
|
||||
},
|
||||
percentileThreshold,
|
||||
durationMinOverride: durationMin,
|
||||
durationMaxOverride: durationMax,
|
||||
searchMetrics: searchAggregatedTransactions,
|
||||
});
|
||||
},
|
||||
|
|
|
@ -18,6 +18,8 @@ export interface OverallLatencyDistributionOptions {
|
|||
}
|
||||
|
||||
export interface OverallLatencyDistributionResponse {
|
||||
durationMin?: number;
|
||||
durationMax?: number;
|
||||
totalDocCount?: number;
|
||||
percentileThresholdValue?: number | null;
|
||||
overallHistogram?: Array<{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue