From 40568857496f45c68a1360e3a6ff59e0a4d7c00a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Tue, 16 Jun 2020 22:56:53 +0200 Subject: [PATCH] [APM] Fix confusing request/minute viz (#69143) (#69249) --- .../shared/charts/TransactionCharts/index.tsx | 4 +- .../__tests__/chartSelectors.test.ts | 29 +- .../apm/public/selectors/chartSelectors.ts | 7 +- .../__snapshots__/transform.test.ts.snap | 491 +++++++++--------- .../charts/get_timeseries_data/index.ts | 2 + .../get_timeseries_data/transform.test.ts | 29 +- .../charts/get_timeseries_data/transform.ts | 53 +- 7 files changed, 327 insertions(+), 288 deletions(-) diff --git a/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx index 915b55f29ef8..4821e06419e3 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx @@ -24,10 +24,10 @@ import { Coordinate, TimeSeries } from '../../../../../typings/timeseries'; import { ITransactionChartData } from '../../../../selectors/chartSelectors'; import { IUrlParams } from '../../../../context/UrlParamsContext/types'; import { - asInteger, tpmUnit, TimeFormatter, getDurationFormatter, + asDecimal, } from '../../../../utils/formatters'; import { MLJobLink } from '../../Links/MachineLearningLinks/MLJobLink'; import { LicenseContext } from '../../../../context/LicenseContext'; @@ -86,7 +86,7 @@ export class TransactionCharts extends Component { public getTPMFormatter = (t: number) => { const { urlParams } = this.props; const unit = tpmUnit(urlParams.transactionType); - return `${asInteger(t)} ${unit}`; + return `${asDecimal(t)} ${unit}`; }; public getTPMTooltipFormatter = (p: Coordinate) => { diff --git a/x-pack/plugins/apm/public/selectors/__tests__/chartSelectors.test.ts b/x-pack/plugins/apm/public/selectors/__tests__/chartSelectors.test.ts index 2f0a30a5019a..901e6052bbf0 100644 --- a/x-pack/plugins/apm/public/selectors/__tests__/chartSelectors.test.ts +++ b/x-pack/plugins/apm/public/selectors/__tests__/chartSelectors.test.ts @@ -15,6 +15,8 @@ import { warningColor, errorColor, } from '../../utils/httpStatusCodeToColor'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { ApmTimeSeriesResponse } from '../../../server/lib/transactions/charts/get_timeseries_data/transform'; describe('chartSelectors', () => { describe('getAnomalyScoreSeries', () => { @@ -98,7 +100,7 @@ describe('chartSelectors', () => { }); describe('getTpmSeries', () => { - const apmTimeseries = { + const apmTimeseries: ApmTimeSeriesResponse = { responseTimes: { avg: [], p95: [], @@ -107,13 +109,14 @@ describe('chartSelectors', () => { tpmBuckets: [ { key: 'HTTP 2xx', + avg: 3.5, dataPoints: [ { x: 0, y: 5 }, - { x: 0, y: 2 }, + { x: 1, y: 2 }, ], }, - { key: 'HTTP 4xx', dataPoints: [{ x: 0, y: 1 }] }, - { key: 'HTTP 5xx', dataPoints: [{ x: 0, y: 0 }] }, + { key: 'HTTP 4xx', avg: 1, dataPoints: [{ x: 0, y: 1 }] }, + { key: 'HTTP 5xx', avg: 0, dataPoints: [{ x: 0, y: 0 }] }, ], overallAvgDuration: 200, }; @@ -125,7 +128,7 @@ describe('chartSelectors', () => { color: successColor, data: [ { x: 0, y: 5 }, - { x: 0, y: 2 }, + { x: 1, y: 2 }, ], legendValue: '3.5 tpm', title: 'HTTP 2xx', @@ -154,7 +157,7 @@ describe('chartSelectors', () => { expect( getTpmSeries({ ...apmTimeseries, - tpmBuckets: [{ key, dataPoints: [{ x: 0, y: 0 }] }], + tpmBuckets: [{ key, avg: 0, dataPoints: [{ x: 0, y: 0 }] }], })[0].color ).toEqual(theme.euiColorSecondary); }); @@ -166,7 +169,7 @@ describe('chartSelectors', () => { expect( getTpmSeries({ ...apmTimeseries, - tpmBuckets: [{ key, dataPoints: [{ x: 0, y: 0 }] }], + tpmBuckets: [{ key, avg: 0, dataPoints: [{ x: 0, y: 0 }] }], })[0].color ).toEqual(theme.euiColorSecondary); }); @@ -178,7 +181,7 @@ describe('chartSelectors', () => { expect( getTpmSeries({ ...apmTimeseries, - tpmBuckets: [{ key, dataPoints: [{ x: 0, y: 0 }] }], + tpmBuckets: [{ key, avg: 0, dataPoints: [{ x: 0, y: 0 }] }], })[0].color ).toEqual(theme.euiColorSecondary); }); @@ -190,7 +193,7 @@ describe('chartSelectors', () => { expect( getTpmSeries({ ...apmTimeseries, - tpmBuckets: [{ key, dataPoints: [{ x: 0, y: 0 }] }], + tpmBuckets: [{ key, avg: 0, dataPoints: [{ x: 0, y: 0 }] }], })[0].color ).toEqual(theme.euiColorSecondary); }); @@ -202,7 +205,7 @@ describe('chartSelectors', () => { expect( getTpmSeries({ ...apmTimeseries, - tpmBuckets: [{ key, dataPoints: [{ x: 0, y: 0 }] }], + tpmBuckets: [{ key, avg: 0, dataPoints: [{ x: 0, y: 0 }] }], })[0].color ).toEqual(theme.euiColorDanger); }); @@ -214,7 +217,7 @@ describe('chartSelectors', () => { expect( getTpmSeries({ ...apmTimeseries, - tpmBuckets: [{ key, dataPoints: [{ x: 0, y: 0 }] }], + tpmBuckets: [{ key, avg: 0, dataPoints: [{ x: 0, y: 0 }] }], })[0].color ).toEqual(theme.euiColorDanger); }); @@ -226,7 +229,7 @@ describe('chartSelectors', () => { expect( getTpmSeries({ ...apmTimeseries, - tpmBuckets: [{ key, dataPoints: [{ x: 0, y: 0 }] }], + tpmBuckets: [{ key, avg: 0, dataPoints: [{ x: 0, y: 0 }] }], })[0].color ).toEqual(theme.euiColorDanger); }); @@ -238,7 +241,7 @@ describe('chartSelectors', () => { expect( getTpmSeries({ ...apmTimeseries, - tpmBuckets: [{ key, dataPoints: [{ x: 0, y: 0 }] }], + tpmBuckets: [{ key, avg: 0, dataPoints: [{ x: 0, y: 0 }] }], })[0].color ).toEqual(theme.euiColorDanger); }); diff --git a/x-pack/plugins/apm/public/selectors/chartSelectors.ts b/x-pack/plugins/apm/public/selectors/chartSelectors.ts index f8aed9dcf6d9..714d62a703f5 100644 --- a/x-pack/plugins/apm/public/selectors/chartSelectors.ts +++ b/x-pack/plugins/apm/public/selectors/chartSelectors.ts @@ -7,7 +7,6 @@ import theme from '@elastic/eui/dist/eui_theme_light.json'; import { i18n } from '@kbn/i18n'; import { difference, zipObject } from 'lodash'; -import mean from 'lodash.mean'; import { rgba } from 'polished'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { TimeSeriesAPIResponse } from '../../server/lib/transactions/charts'; @@ -72,7 +71,6 @@ export function getResponseTimeSeries({ }: TimeSeriesAPIResponse) { const { overallAvgDuration } = apmTimeseries; const { avg, p95, p99 } = apmTimeseries.responseTimes; - const formattedDuration = asDuration(overallAvgDuration); const series: TimeSeries[] = [ { @@ -80,7 +78,7 @@ export function getResponseTimeSeries({ defaultMessage: 'Avg.', }), data: avg, - legendValue: formattedDuration, + legendValue: asDuration(overallAvgDuration), type: 'linemark', color: theme.euiColorVis1, }, @@ -171,11 +169,10 @@ export function getTpmSeries( } return tpmBuckets.map((bucket) => { - const average = mean(bucket.dataPoints.map((p) => p.y)); return { title: bucket.key, data: bucket.dataPoints, - legendValue: `${asDecimal(average)} ${tpmUnit(transactionType || '')}`, + legendValue: `${asDecimal(bucket.avg)} ${tpmUnit(transactionType || '')}`, type: 'linemark', color: getColor(bucket.key), }; diff --git a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/__snapshots__/transform.test.ts.snap b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/__snapshots__/transform.test.ts.snap index e99c32d933b0..fc9edb496784 100644 --- a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/__snapshots__/transform.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/__snapshots__/transform.test.ts.snap @@ -985,326 +985,327 @@ Object { }, "tpmBuckets": Array [ Object { + "avg": 112708, "dataPoints": Array [ Object { "x": 1528113600000, - "y": 82230, + "y": 8223, }, Object { "x": 1528124400000, - "y": 81460, + "y": 8146, }, Object { "x": 1528135200000, - "y": 82320, + "y": 8232, }, Object { "x": 1528146000000, - "y": 82485, + "y": 8248.5, }, Object { "x": 1528156800000, - "y": 83995, + "y": 8399.5, }, Object { "x": 1528167600000, - "y": 82805, + "y": 8280.5, }, Object { "x": 1528178400000, - "y": 82155, + "y": 8215.5, }, Object { "x": 1528189200000, - "y": 81915, + "y": 8191.5, }, Object { "x": 1528200000000, - "y": 81475, + "y": 8147.5, }, Object { "x": 1528210800000, - "y": 83510, + "y": 8351, }, Object { "x": 1528221600000, - "y": 82345, + "y": 8234.5, }, Object { "x": 1528232400000, - "y": 82330, + "y": 8233, }, Object { "x": 1528243200000, - "y": 82755, + "y": 8275.5, }, Object { "x": 1528254000000, - "y": 83375, + "y": 8337.5, }, Object { "x": 1528264800000, - "y": 82050, + "y": 8205, }, Object { "x": 1528275600000, - "y": 81235, + "y": 8123.5, }, Object { "x": 1528286400000, - "y": 75725, + "y": 7572.5, }, Object { "x": 1528297200000, - "y": 80890, + "y": 8089, }, Object { "x": 1528308000000, - "y": 82650, + "y": 8265, }, Object { "x": 1528318800000, - "y": 81055, + "y": 8105.5, }, Object { "x": 1528329600000, - "y": 82265, + "y": 8226.5, }, Object { "x": 1528340400000, - "y": 82515, + "y": 8251.5, }, Object { "x": 1528351200000, - "y": 83020, + "y": 8302, }, Object { "x": 1528362000000, - "y": 82610, + "y": 8261, }, Object { "x": 1528372800000, - "y": 80820, + "y": 8082, }, Object { "x": 1528383600000, - "y": 82600, + "y": 8260, }, Object { "x": 1528394400000, - "y": 82670, + "y": 8267, }, Object { "x": 1528405200000, - "y": 81555, + "y": 8155.5, }, Object { "x": 1528416000000, - "y": 83350, + "y": 8335, }, Object { "x": 1528426800000, - "y": 80960, + "y": 8096, }, Object { "x": 1528437600000, - "y": 82895, + "y": 8289.5, }, Object { "x": 1528448400000, - "y": 81650, + "y": 8165, }, Object { "x": 1528459200000, - "y": 82825, + "y": 8282.5, }, Object { "x": 1528470000000, - "y": 82715, + "y": 8271.5, }, Object { "x": 1528480800000, - "y": 82460, + "y": 8246, }, Object { "x": 1528491600000, - "y": 82020, + "y": 8202, }, Object { "x": 1528502400000, - "y": 22640, + "y": 2264, }, Object { "x": 1528513200000, - "y": 22785, + "y": 2278.5, }, Object { "x": 1528524000000, - "y": 22830, + "y": 2283, }, Object { "x": 1528534800000, - "y": 22930, + "y": 2293, }, Object { "x": 1528545600000, - "y": 23360, + "y": 2336, }, Object { "x": 1528556400000, - "y": 23425, + "y": 2342.5, }, Object { "x": 1528567200000, - "y": 22605, + "y": 2260.5, }, Object { "x": 1528578000000, - "y": 23060, + "y": 2306, }, Object { "x": 1528588800000, - "y": 22675, + "y": 2267.5, }, Object { "x": 1528599600000, - "y": 23030, + "y": 2303, }, Object { "x": 1528610400000, - "y": 23070, + "y": 2307, }, Object { "x": 1528621200000, - "y": 22535, + "y": 2253.5, }, Object { "x": 1528632000000, - "y": 23055, + "y": 2305.5, }, Object { "x": 1528642800000, - "y": 22935, + "y": 2293.5, }, Object { "x": 1528653600000, - "y": 22910, + "y": 2291, }, Object { "x": 1528664400000, - "y": 23075, + "y": 2307.5, }, Object { "x": 1528675200000, - "y": 81255, + "y": 8125.5, }, Object { "x": 1528686000000, - "y": 84125, + "y": 8412.5, }, Object { "x": 1528696800000, - "y": 81440, + "y": 8144, }, Object { "x": 1528707600000, - "y": 82460, + "y": 8246, }, Object { "x": 1528718400000, - "y": 82170, + "y": 8217, }, Object { "x": 1528729200000, - "y": 85015, + "y": 8501.5, }, Object { "x": 1528740000000, - "y": 81820, + "y": 8182, }, Object { "x": 1528750800000, - "y": 83225, + "y": 8322.5, }, Object { "x": 1528761600000, - "y": 83475, + "y": 8347.5, }, Object { "x": 1528772400000, - "y": 82490, + "y": 8249, }, Object { "x": 1528783200000, - "y": 82940, + "y": 8294, }, Object { "x": 1528794000000, - "y": 83425, + "y": 8342.5, }, Object { "x": 1528804800000, - "y": 81805, + "y": 8180.5, }, Object { "x": 1528815600000, - "y": 83290, + "y": 8329, }, Object { "x": 1528826400000, - "y": 82535, + "y": 8253.5, }, Object { "x": 1528837200000, - "y": 82090, + "y": 8209, }, Object { "x": 1528848000000, - "y": 82385, + "y": 8238.5, }, Object { "x": 1528858800000, - "y": 83775, + "y": 8377.5, }, Object { "x": 1528869600000, - "y": 82970, + "y": 8297, }, Object { "x": 1528880400000, - "y": 84060, + "y": 8406, }, Object { "x": 1528891200000, - "y": 84315, + "y": 8431.5, }, Object { "x": 1528902000000, - "y": 83275, + "y": 8327.5, }, Object { "x": 1528912800000, - "y": 83615, + "y": 8361.5, }, Object { "x": 1528923600000, - "y": 82885, + "y": 8288.5, }, Object { "x": 1528934400000, - "y": 75625, + "y": 7562.5, }, Object { "x": 1528945200000, - "y": 82160, + "y": 8216, }, Object { "x": 1528956000000, - "y": 82320, + "y": 8232, }, Object { "x": 1528966800000, - "y": 81845, + "y": 8184.5, }, Object { "x": 1528977600000, @@ -1314,6 +1315,7 @@ Object { "key": "HTTP 2xx", }, Object { + "avg": 665, "dataPoints": Array [ Object { "x": 1528113600000, @@ -1381,11 +1383,11 @@ Object { }, Object { "x": 1528286400000, - "y": 20205, + "y": 2020.5, }, Object { "x": 1528297200000, - "y": 2270, + "y": 227, }, Object { "x": 1528308000000, @@ -1621,7 +1623,7 @@ Object { }, Object { "x": 1528934400000, - "y": 10775, + "y": 1077.5, }, Object { "x": 1528945200000, @@ -1643,326 +1645,327 @@ Object { "key": "HTTP 3xx", }, Object { + "avg": 8190.7, "dataPoints": Array [ Object { "x": 1528113600000, - "y": 5930, + "y": 593, }, Object { "x": 1528124400000, - "y": 6065, + "y": 606.5, }, Object { "x": 1528135200000, - "y": 6025, + "y": 602.5, }, Object { "x": 1528146000000, - "y": 5810, + "y": 581, }, Object { "x": 1528156800000, - "y": 6190, + "y": 619, }, Object { "x": 1528167600000, - "y": 5955, + "y": 595.5, }, Object { "x": 1528178400000, - "y": 6370, + "y": 637, }, Object { "x": 1528189200000, - "y": 6170, + "y": 617, }, Object { "x": 1528200000000, - "y": 5820, + "y": 582, }, Object { "x": 1528210800000, - "y": 6165, + "y": 616.5, }, Object { "x": 1528221600000, - "y": 6115, + "y": 611.5, }, Object { "x": 1528232400000, - "y": 6080, + "y": 608, }, Object { "x": 1528243200000, - "y": 6000, + "y": 600, }, Object { "x": 1528254000000, - "y": 6185, + "y": 618.5, }, Object { "x": 1528264800000, - "y": 6155, + "y": 615.5, }, Object { "x": 1528275600000, - "y": 5910, + "y": 591, }, Object { "x": 1528286400000, - "y": 5625, + "y": 562.5, }, Object { "x": 1528297200000, - "y": 6215, + "y": 621.5, }, Object { "x": 1528308000000, - "y": 6235, + "y": 623.5, }, Object { "x": 1528318800000, - "y": 5815, + "y": 581.5, }, Object { "x": 1528329600000, - "y": 6100, + "y": 610, }, Object { "x": 1528340400000, - "y": 6010, + "y": 601, }, Object { "x": 1528351200000, - "y": 5960, + "y": 596, }, Object { "x": 1528362000000, - "y": 6240, + "y": 624, }, Object { "x": 1528372800000, - "y": 5945, + "y": 594.5, }, Object { "x": 1528383600000, - "y": 6150, + "y": 615, }, Object { "x": 1528394400000, - "y": 6030, + "y": 603, }, Object { "x": 1528405200000, - "y": 5950, + "y": 595, }, Object { "x": 1528416000000, - "y": 6160, + "y": 616, }, Object { "x": 1528426800000, - "y": 5855, + "y": 585.5, }, Object { "x": 1528437600000, - "y": 6160, + "y": 616, }, Object { "x": 1528448400000, - "y": 6265, + "y": 626.5, }, Object { "x": 1528459200000, - "y": 6250, + "y": 625, }, Object { "x": 1528470000000, - "y": 5835, + "y": 583.5, }, Object { "x": 1528480800000, - "y": 6290, + "y": 629, }, Object { "x": 1528491600000, - "y": 5740, + "y": 574, }, Object { "x": 1528502400000, - "y": 1420, + "y": 142, }, Object { "x": 1528513200000, - "y": 1200, + "y": 120, }, Object { "x": 1528524000000, - "y": 1365, + "y": 136.5, }, Object { "x": 1528534800000, - "y": 1475, + "y": 147.5, }, Object { "x": 1528545600000, - "y": 1405, + "y": 140.5, }, Object { "x": 1528556400000, - "y": 1500, + "y": 150, }, Object { "x": 1528567200000, - "y": 1320, + "y": 132, }, Object { "x": 1528578000000, - "y": 1300, + "y": 130, }, Object { "x": 1528588800000, - "y": 1395, + "y": 139.5, }, Object { "x": 1528599600000, - "y": 1295, + "y": 129.5, }, Object { "x": 1528610400000, - "y": 1455, + "y": 145.5, }, Object { "x": 1528621200000, - "y": 1240, + "y": 124, }, Object { "x": 1528632000000, - "y": 1555, + "y": 155.5, }, Object { "x": 1528642800000, - "y": 1385, + "y": 138.5, }, Object { "x": 1528653600000, - "y": 1395, + "y": 139.5, }, Object { "x": 1528664400000, - "y": 1375, + "y": 137.5, }, Object { "x": 1528675200000, - "y": 5835, + "y": 583.5, }, Object { "x": 1528686000000, - "y": 6350, + "y": 635, }, Object { "x": 1528696800000, - "y": 5815, + "y": 581.5, }, Object { "x": 1528707600000, - "y": 5775, + "y": 577.5, }, Object { "x": 1528718400000, - "y": 6085, + "y": 608.5, }, Object { "x": 1528729200000, - "y": 6135, + "y": 613.5, }, Object { "x": 1528740000000, - "y": 5970, + "y": 597, }, Object { "x": 1528750800000, - "y": 5765, + "y": 576.5, }, Object { "x": 1528761600000, - "y": 6055, + "y": 605.5, }, Object { "x": 1528772400000, - "y": 6015, + "y": 601.5, }, Object { "x": 1528783200000, - "y": 6345, + "y": 634.5, }, Object { "x": 1528794000000, - "y": 5985, + "y": 598.5, }, Object { "x": 1528804800000, - "y": 5920, + "y": 592, }, Object { "x": 1528815600000, - "y": 5880, + "y": 588, }, Object { "x": 1528826400000, - "y": 5810, + "y": 581, }, Object { "x": 1528837200000, - "y": 6350, + "y": 635, }, Object { "x": 1528848000000, - "y": 6120, + "y": 612, }, Object { "x": 1528858800000, - "y": 6275, + "y": 627.5, }, Object { "x": 1528869600000, - "y": 6035, + "y": 603.5, }, Object { "x": 1528880400000, - "y": 6030, + "y": 603, }, Object { "x": 1528891200000, - "y": 6270, + "y": 627, }, Object { "x": 1528902000000, - "y": 6080, + "y": 608, }, Object { "x": 1528912800000, - "y": 6315, + "y": 631.5, }, Object { "x": 1528923600000, - "y": 6385, + "y": 638.5, }, Object { "x": 1528934400000, - "y": 5915, + "y": 591.5, }, Object { "x": 1528945200000, - "y": 6105, + "y": 610.5, }, Object { "x": 1528956000000, - "y": 5990, + "y": 599, }, Object { "x": 1528966800000, - "y": 6070, + "y": 607, }, Object { "x": 1528977600000, @@ -1972,326 +1975,327 @@ Object { "key": "HTTP 4xx", }, Object { + "avg": 8203.6, "dataPoints": Array [ Object { "x": 1528113600000, - "y": 6045, + "y": 604.5, }, Object { "x": 1528124400000, - "y": 6015, + "y": 601.5, }, Object { "x": 1528135200000, - "y": 5980, + "y": 598, }, Object { "x": 1528146000000, - "y": 6150, + "y": 615, }, Object { "x": 1528156800000, - "y": 6165, + "y": 616.5, }, Object { "x": 1528167600000, - "y": 6360, + "y": 636, }, Object { "x": 1528178400000, - "y": 6090, + "y": 609, }, Object { "x": 1528189200000, - "y": 6085, + "y": 608.5, }, Object { "x": 1528200000000, - "y": 6175, + "y": 617.5, }, Object { "x": 1528210800000, - "y": 6245, + "y": 624.5, }, Object { "x": 1528221600000, - "y": 5790, + "y": 579, }, Object { "x": 1528232400000, - "y": 6075, + "y": 607.5, }, Object { "x": 1528243200000, - "y": 5955, + "y": 595.5, }, Object { "x": 1528254000000, - "y": 6175, + "y": 617.5, }, Object { "x": 1528264800000, - "y": 6060, + "y": 606, }, Object { "x": 1528275600000, - "y": 5900, + "y": 590, }, Object { "x": 1528286400000, - "y": 5455, + "y": 545.5, }, Object { "x": 1528297200000, - "y": 5880, + "y": 588, }, Object { "x": 1528308000000, - "y": 6215, + "y": 621.5, }, Object { "x": 1528318800000, - "y": 6040, + "y": 604, }, Object { "x": 1528329600000, - "y": 6010, + "y": 601, }, Object { "x": 1528340400000, - "y": 6440, + "y": 644, }, Object { "x": 1528351200000, - "y": 6205, + "y": 620.5, }, Object { "x": 1528362000000, - "y": 6075, + "y": 607.5, }, Object { "x": 1528372800000, - "y": 5760, + "y": 576, }, Object { "x": 1528383600000, - "y": 6205, + "y": 620.5, }, Object { "x": 1528394400000, - "y": 5885, + "y": 588.5, }, Object { "x": 1528405200000, - "y": 6215, + "y": 621.5, }, Object { "x": 1528416000000, - "y": 6275, + "y": 627.5, }, Object { "x": 1528426800000, - "y": 5945, + "y": 594.5, }, Object { "x": 1528437600000, - "y": 5915, + "y": 591.5, }, Object { "x": 1528448400000, - "y": 6075, + "y": 607.5, }, Object { "x": 1528459200000, - "y": 6410, + "y": 641, }, Object { "x": 1528470000000, - "y": 5885, + "y": 588.5, }, Object { "x": 1528480800000, - "y": 5995, + "y": 599.5, }, Object { "x": 1528491600000, - "y": 6170, + "y": 617, }, Object { "x": 1528502400000, - "y": 1420, + "y": 142, }, Object { "x": 1528513200000, - "y": 1535, + "y": 153.5, }, Object { "x": 1528524000000, - "y": 1415, + "y": 141.5, }, Object { "x": 1528534800000, - "y": 1515, + "y": 151.5, }, Object { "x": 1528545600000, - "y": 1630, + "y": 163, }, Object { "x": 1528556400000, - "y": 1345, + "y": 134.5, }, Object { "x": 1528567200000, - "y": 1485, + "y": 148.5, }, Object { "x": 1528578000000, - "y": 1390, + "y": 139, }, Object { "x": 1528588800000, - "y": 1445, + "y": 144.5, }, Object { "x": 1528599600000, - "y": 1360, + "y": 136, }, Object { "x": 1528610400000, - "y": 1395, + "y": 139.5, }, Object { "x": 1528621200000, - "y": 1190, + "y": 119, }, Object { "x": 1528632000000, - "y": 1440, + "y": 144, }, Object { "x": 1528642800000, - "y": 1290, + "y": 129, }, Object { "x": 1528653600000, - "y": 1320, + "y": 132, }, Object { "x": 1528664400000, - "y": 1480, + "y": 148, }, Object { "x": 1528675200000, - "y": 6065, + "y": 606.5, }, Object { "x": 1528686000000, - "y": 6270, + "y": 627, }, Object { "x": 1528696800000, - "y": 5675, + "y": 567.5, }, Object { "x": 1528707600000, - "y": 6200, + "y": 620, }, Object { "x": 1528718400000, - "y": 6075, + "y": 607.5, }, Object { "x": 1528729200000, - "y": 6195, + "y": 619.5, }, Object { "x": 1528740000000, - "y": 6045, + "y": 604.5, }, Object { "x": 1528750800000, - "y": 6040, + "y": 604, }, Object { "x": 1528761600000, - "y": 5880, + "y": 588, }, Object { "x": 1528772400000, - "y": 6035, + "y": 603.5, }, Object { "x": 1528783200000, - "y": 5990, + "y": 599, }, Object { "x": 1528794000000, - "y": 5825, + "y": 582.5, }, Object { "x": 1528804800000, - "y": 5940, + "y": 594, }, Object { "x": 1528815600000, - "y": 6225, + "y": 622.5, }, Object { "x": 1528826400000, - "y": 6190, + "y": 619, }, Object { "x": 1528837200000, - "y": 6415, + "y": 641.5, }, Object { "x": 1528848000000, - "y": 5990, + "y": 599, }, Object { "x": 1528858800000, - "y": 5860, + "y": 586, }, Object { "x": 1528869600000, - "y": 6145, + "y": 614.5, }, Object { "x": 1528880400000, - "y": 6195, + "y": 619.5, }, Object { "x": 1528891200000, - "y": 6155, + "y": 615.5, }, Object { "x": 1528902000000, - "y": 6240, + "y": 624, }, Object { "x": 1528912800000, - "y": 6100, + "y": 610, }, Object { "x": 1528923600000, - "y": 6120, + "y": 612, }, Object { "x": 1528934400000, - "y": 5440, + "y": 544, }, Object { "x": 1528945200000, - "y": 6175, + "y": 617.5, }, Object { "x": 1528956000000, - "y": 5805, + "y": 580.5, }, Object { "x": 1528966800000, - "y": 5915, + "y": 591.5, }, Object { "x": 1528977600000, @@ -2301,6 +2305,7 @@ Object { "key": "HTTP 5xx", }, Object { + "avg": 0, "dataPoints": Array [], "key": "A Custom Bucket (that should be last)", }, diff --git a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/index.ts b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/index.ts index 0f1eca5853bb..8a0fe1a57736 100644 --- a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/index.ts @@ -21,10 +21,12 @@ export async function getApmTimeseriesData(options: { }) { const { start, end } = options.setup; const { bucketSize } = getBucketSize(start, end, 'auto'); + const durationAsMinutes = (end - start) / 1000 / 60; const timeseriesResponse = await timeseriesFetcher(options); return timeseriesTransformer({ timeseriesResponse, bucketSize, + durationAsMinutes, }); } diff --git a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/transform.test.ts b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/transform.test.ts index abce5dbe1805..d0d0875be388 100644 --- a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/transform.test.ts +++ b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/transform.test.ts @@ -16,7 +16,8 @@ describe('timeseriesTransformer', () => { beforeEach(async () => { res = await timeseriesTransformer({ timeseriesResponse, - bucketSize: 12, + bucketSize: 120, + durationAsMinutes: 10, }); }); @@ -79,7 +80,7 @@ describe('getTpmBuckets', () => { { key_as_string: '', key: 1, - doc_count: 500, + doc_count: 100, }, { key_as_string: '', @@ -95,23 +96,31 @@ describe('getTpmBuckets', () => { }, }, ]; - const bucketSize = 10; - expect(getTpmBuckets(buckets as any, bucketSize)).toEqual([ + + expect( + getTpmBuckets({ + transactionResultBuckets: buckets, + bucketSize: 120, + durationAsMinutes: 10, + }) + ).toEqual([ { + avg: 90, dataPoints: [ { x: 0, y: 0 }, - { x: 1, y: 1200 }, - { x: 2, y: 1800 }, - { x: 3, y: 2400 }, + { x: 1, y: 100 }, + { x: 2, y: 150 }, + { x: 3, y: 200 }, ], key: 'HTTP 4xx', }, { + avg: 50, dataPoints: [ { x: 0, y: 0 }, - { x: 1, y: 3000 }, - { x: 2, y: 600 }, - { x: 3, y: 1800 }, + { x: 1, y: 50 }, + { x: 2, y: 50 }, + { x: 3, y: 150 }, ], key: 'HTTP 5xx', }, diff --git a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/transform.ts b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/transform.ts index bbdd0bd3e054..f68c069253b9 100644 --- a/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/transform.ts +++ b/x-pack/plugins/apm/server/lib/transactions/charts/get_timeseries_data/transform.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { isNumber, round, sortBy } from 'lodash'; +import { isNumber, sortBy } from 'lodash'; import { NOT_AVAILABLE_LABEL } from '../../../../../common/i18n'; import { Coordinate } from '../../../../../typings/timeseries'; import { ESResponse } from './fetcher'; @@ -14,16 +14,22 @@ export type ApmTimeSeriesResponse = ReturnType; export function timeseriesTransformer({ timeseriesResponse, bucketSize, + durationAsMinutes, }: { timeseriesResponse: ESResponse; bucketSize: number; + durationAsMinutes: number; }) { const aggs = timeseriesResponse.aggregations; const overallAvgDuration = aggs?.overall_avg_duration.value || null; const responseTimeBuckets = aggs?.response_times.buckets || []; const { avg, p95, p99 } = getResponseTime(responseTimeBuckets); const transactionResultBuckets = aggs?.transaction_results.buckets || []; - const tpmBuckets = getTpmBuckets(transactionResultBuckets, bucketSize); + const tpmBuckets = getTpmBuckets({ + transactionResultBuckets, + bucketSize, + durationAsMinutes, + }); return { responseTimes: { @@ -36,18 +42,28 @@ export function timeseriesTransformer({ }; } -export function getTpmBuckets( - transactionResultBuckets: Required< - ESResponse - >['aggregations']['transaction_results']['buckets'] = [], - bucketSize: number -) { +type TransactionResultBuckets = Required< + ESResponse +>['aggregations']['transaction_results']['buckets']; + +export function getTpmBuckets({ + transactionResultBuckets = [], + bucketSize, + durationAsMinutes, +}: { + transactionResultBuckets: TransactionResultBuckets; + bucketSize: number; + durationAsMinutes: number; +}) { const buckets = transactionResultBuckets.map( ({ key: resultKey, timeseries }) => { const dataPoints = timeseries.buckets.map((bucket) => { + // calculate request/minute. Avoid up-scaling numbers if bucketSize is below 60s (1 minute). + // Eg. 1 request during a 10 second window should be displayed as "1 rpm" instead of "6 rpm". + const tmpValue = bucket.doc_count * (60 / Math.max(60, bucketSize)); return { x: bucket.key, - y: round(bucket.doc_count * (60 / bucketSize), 1), + y: tmpValue, }; }); @@ -55,7 +71,14 @@ export function getTpmBuckets( const key = resultKey === '' ? NOT_AVAILABLE_LABEL : (resultKey as string); - return { key, dataPoints }; + const docCountTotal = timeseries.buckets + .map((bucket) => bucket.doc_count) + .reduce((a, b) => a + b, 0); + + // calculate request/minute + const avg = docCountTotal / durationAsMinutes; + + return { key, dataPoints, avg }; } ); @@ -65,11 +88,11 @@ export function getTpmBuckets( ); } -function getResponseTime( - responseTimeBuckets: Required< - ESResponse - >['aggregations']['response_times']['buckets'] = [] -) { +type ResponseTimeBuckets = Required< + ESResponse +>['aggregations']['response_times']['buckets']; + +function getResponseTime(responseTimeBuckets: ResponseTimeBuckets = []) { return responseTimeBuckets.reduce( (acc, bucket) => { const { '95.0': p95, '99.0': p99 } = bucket.pct.values;