From 3d5dc29fa8cf8be59e1d39fb102ed87029b85462 Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Mon, 15 Feb 2021 08:55:28 -0500 Subject: [PATCH 01/13] adding comparison to transactions table --- .../get_columns.tsx | 60 +++++++++--- .../index.tsx | 27 +++++- .../components/shared/ImpactBar/index.tsx | 12 +-- .../shared/charts/spark_plot/index.tsx | 23 ++++- ...transaction_group_comparison_statistics.ts | 95 +++++++++---------- .../plugins/apm/server/routes/transactions.ts | 60 +++++++++++- 6 files changed, 196 insertions(+), 81 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx index 2ffc0fc9c93a3..82cfac5364ce5 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiBasicTableColumn } from '@elastic/eui'; +import { EuiBasicTableColumn, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { ValuesType } from 'utility-types'; @@ -54,10 +54,12 @@ export function getColumns({ serviceName, latencyAggregationType, transactionGroupComparisonStatistics, + comparisonEnabled = true, }: { serviceName: string; latencyAggregationType?: string; transactionGroupComparisonStatistics?: TransactionGroupComparisonStatistics; + comparisonEnabled?: boolean; }): Array> { return [ { @@ -91,13 +93,18 @@ export function getColumns({ name: getLatencyAggregationTypeLabel(latencyAggregationType), width: px(unit * 10), render: (_, { latency, name }) => { - const timeseries = - transactionGroupComparisonStatistics?.[name]?.latency; + const currentTimeseries = + transactionGroupComparisonStatistics?.currentPeriod?.[name]?.latency; + const previousTimeseries = + transactionGroupComparisonStatistics?.previousPeriod?.[name]?.latency; return ( ); @@ -112,13 +119,20 @@ export function getColumns({ ), width: px(unit * 10), render: (_, { throughput, name }) => { - const timeseries = - transactionGroupComparisonStatistics?.[name]?.throughput; + const currentTimeseries = + transactionGroupComparisonStatistics?.currentPeriod?.[name] + ?.throughput; + const previousTimeseries = + transactionGroupComparisonStatistics?.previousPeriod?.[name] + ?.throughput; return ( ); @@ -133,13 +147,20 @@ export function getColumns({ ), width: px(unit * 8), render: (_, { errorRate, name }) => { - const timeseries = - transactionGroupComparisonStatistics?.[name]?.errorRate; + const currentTimeseries = + transactionGroupComparisonStatistics?.currentPeriod?.[name] + ?.errorRate; + const previousTimeseries = + transactionGroupComparisonStatistics?.previousPeriod?.[name] + ?.errorRate; return ( ); @@ -154,9 +175,22 @@ export function getColumns({ ), width: px(unit * 5), render: (_, { name }) => { - const impact = - transactionGroupComparisonStatistics?.[name]?.impact ?? 0; - return ; + const currenIimpact = + transactionGroupComparisonStatistics?.currentPeriod?.[name]?.impact ?? + 0; + const previousIimpact = + transactionGroupComparisonStatistics?.previousPeriod?.[name] + ?.impact ?? 0; + return ( + + + + + + + + + ); }, }, ]; diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx index a0facb2ddbedf..f1712f343c0b9 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx @@ -20,6 +20,7 @@ import { useUrlParams } from '../../../../context/url_params_context/use_url_par import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher'; import { TransactionOverviewLink } from '../../../shared/Links/apm/transaction_overview_link'; import { TableFetchWrapper } from '../../../shared/table_fetch_wrapper'; +import { getTimeRangeComparison } from '../../../shared/time_comparison/get_time_range_comparison'; import { ServiceOverviewTableContainer } from '../service_overview_table_container'; import { getColumns } from './get_columns'; @@ -58,9 +59,26 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { const { transactionType } = useApmServiceContext(); const { uiFilters, - urlParams: { start, end, latencyAggregationType }, + urlParams: { + start, + end, + latencyAggregationType, + comparisonType, + comparisonEnabled, + }, } = useUrlParams(); + const { + comparisonStart = undefined, + comparisonEnd = undefined, + } = comparisonType + ? getTimeRangeComparison({ + start, + end, + comparisonType, + }) + : {}; + const { data = INITIAL_STATE, status } = useFetcher( (callApmApi) => { if (!start || !end || !latencyAggregationType || !transactionType) { @@ -132,14 +150,16 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { transactionType, latencyAggregationType, transactionNames, + comparisonStart, + comparisonEnd, }, }, }); } }, - // only fetches statistics when requestId changes or transaction names changes + // only fetches statistics when requestId, transaction names or comparison range change // eslint-disable-next-line react-hooks/exhaustive-deps - [requestId, transactionNames], + [requestId, transactionNames, comparisonStart, comparisonEnd], { preservePreviousData: false } ); @@ -147,6 +167,7 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { serviceName, latencyAggregationType, transactionGroupComparisonStatistics, + comparisonEnabled, }); const isLoading = diff --git a/x-pack/plugins/apm/public/components/shared/ImpactBar/index.tsx b/x-pack/plugins/apm/public/components/shared/ImpactBar/index.tsx index 3497bb462b0fe..92f488b8ba0ee 100644 --- a/x-pack/plugins/apm/public/components/shared/ImpactBar/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/ImpactBar/index.tsx @@ -11,23 +11,19 @@ import React from 'react'; // TODO: extend from EUI's EuiProgress prop interface export interface ImpactBarProps extends Record { value: number; - size?: 'l' | 'm'; + size?: 's' | 'l' | 'm'; max?: number; + color?: string; } export function ImpactBar({ value, size = 'l', max = 100, + color = 'primary', ...rest }: ImpactBarProps) { return ( - + ); } diff --git a/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx index 36c499f9e5ee4..2336a547d4f01 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx @@ -12,6 +12,7 @@ import { AreaSeries, Chart, CurveType, + LineSeries, ScaleType, Settings, } from '@elastic/charts'; @@ -20,6 +21,7 @@ import { Coordinate } from '../../../../../typings/timeseries'; import { useChartTheme } from '../../../../../../observability/public'; import { px, unit } from '../../../../style/variables'; import { useTheme } from '../../../../hooks/use_theme'; +import { getComparisonChartTheme } from '../../time_comparison/get_time_range_comparison'; type Color = | 'euiColorVis0' @@ -38,23 +40,24 @@ export function SparkPlot({ series, valueLabel, compact, + comparisonSeries = [], }: { color: Color; series?: Coordinate[] | null; valueLabel: React.ReactNode; compact?: boolean; + comparisonSeries?: Coordinate[]; }) { const theme = useTheme(); const defaultChartTheme = useChartTheme(); + const comparisonChartTheme = getComparisonChartTheme(theme); const sparkplotChartTheme = merge({}, defaultChartTheme, { chartMargins: { left: 0, right: 0, top: 0, bottom: 0 }, lineSeriesStyle: { point: { opacity: 0 }, }, - areaSeriesStyle: { - point: { opacity: 0 }, - }, + ...comparisonChartTheme, }); const colorValue = theme.eui[color]; @@ -76,8 +79,8 @@ export function SparkPlot({ showLegend={false} tooltip="none" /> - + )} diff --git a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts index 54cf89d6125b6..6086e855bcf68 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts @@ -27,7 +27,7 @@ import { getLatencyAggregation, getLatencyValue, } from '../helpers/latency_aggregation_type'; -import { Setup, SetupTimeRange } from '../helpers/setup_request'; +import { Setup } from '../helpers/setup_request'; import { calculateTransactionErrorPercentage } from '../helpers/transaction_error_rate'; export async function getServiceTransactionGroupComparisonStatistics({ @@ -38,29 +38,31 @@ export async function getServiceTransactionGroupComparisonStatistics({ searchAggregatedTransactions, transactionType, latencyAggregationType, + start, + end, }: { serviceName: string; transactionNames: string[]; - setup: Setup & SetupTimeRange; + setup: Setup; numBuckets: number; searchAggregatedTransactions: boolean; transactionType: string; latencyAggregationType: LatencyAggregationType; + start: number; + end: number; }): Promise< - Record< - string, - { - latency: Coordinate[]; - throughput: Coordinate[]; - errorRate: Coordinate[]; - impact: number; - } - > + Array<{ + transactionName: string; + latency: Coordinate[]; + throughput: Coordinate[]; + errorRate: Coordinate[]; + impact: number; + }> > { return withApmSpan( 'get_service_transaction_group_comparison_statistics', async () => { - const { apmEventClient, start, end, esFilter } = setup; + const { apmEventClient, esFilter } = setup; const { intervalString } = getBucketSize({ start, end, numBuckets }); const field = getTransactionDurationFieldForAggregatedTransactions( @@ -136,44 +138,39 @@ export async function getServiceTransactionGroupComparisonStatistics({ const buckets = response.aggregations?.transaction_groups.buckets ?? []; const totalDuration = response.aggregations?.total_duration.value; - return keyBy( - buckets.map((bucket) => { - const transactionName = bucket.key; - const latency = bucket.timeseries.buckets.map((timeseriesBucket) => ({ + return buckets.map((bucket) => { + const transactionName = bucket.key as string; + const latency = bucket.timeseries.buckets.map((timeseriesBucket) => ({ + x: timeseriesBucket.key, + y: getLatencyValue({ + latencyAggregationType, + aggregation: timeseriesBucket.latency, + }), + })); + const throughput = bucket.timeseries.buckets.map( + (timeseriesBucket) => ({ x: timeseriesBucket.key, - y: getLatencyValue({ - latencyAggregationType, - aggregation: timeseriesBucket.latency, - }), - })); - const throughput = bucket.timeseries.buckets.map( - (timeseriesBucket) => ({ - x: timeseriesBucket.key, - y: timeseriesBucket.throughput_rate.value, - }) - ); - const errorRate = bucket.timeseries.buckets.map( - (timeseriesBucket) => ({ - x: timeseriesBucket.key, - y: calculateTransactionErrorPercentage( - timeseriesBucket[EVENT_OUTCOME] - ), - }) - ); - const transactionGroupTotalDuration = - bucket.transaction_group_total_duration.value || 0; - return { - transactionName, - latency, - throughput, - errorRate, - impact: totalDuration - ? (transactionGroupTotalDuration * 100) / totalDuration - : 0, - }; - }), - 'transactionName' - ); + y: timeseriesBucket.throughput_rate.value, + }) + ); + const errorRate = bucket.timeseries.buckets.map((timeseriesBucket) => ({ + x: timeseriesBucket.key, + y: calculateTransactionErrorPercentage( + timeseriesBucket[EVENT_OUTCOME] + ), + })); + const transactionGroupTotalDuration = + bucket.transaction_group_total_duration.value || 0; + return { + transactionName, + latency, + throughput, + errorRate, + impact: totalDuration + ? (transactionGroupTotalDuration * 100) / totalDuration + : 0, + }; + }); } ); } diff --git a/x-pack/plugins/apm/server/routes/transactions.ts b/x-pack/plugins/apm/server/routes/transactions.ts index bef96cb7f0767..575bc46d7892e 100644 --- a/x-pack/plugins/apm/server/routes/transactions.ts +++ b/x-pack/plugins/apm/server/routes/transactions.ts @@ -7,6 +7,7 @@ import Boom from '@hapi/boom'; import * as t from 'io-ts'; +import { keyBy } from 'lodash'; import { LatencyAggregationType, latencyAggregationTypeRt, @@ -24,8 +25,9 @@ import { getLatencyTimeseries } from '../lib/transactions/get_latency_charts'; import { getThroughputCharts } from '../lib/transactions/get_throughput_charts'; import { getTransactionGroupList } from '../lib/transaction_groups'; import { getErrorRate } from '../lib/transaction_groups/get_error_rate'; +import { offsetPreviousPeriodCoordinates } from '../utils/offset_previous_period_coordinate'; import { createRoute } from './create_route'; -import { rangeRt, uiFiltersRt } from './default_api_types'; +import { comparisonRangeRt, rangeRt, uiFiltersRt } from './default_api_types'; /** * Returns a list of transactions grouped by name @@ -111,6 +113,7 @@ export const transactionGroupsComparisonStatisticsRoute = createRoute({ path: t.type({ serviceName: t.string }), query: t.intersection([ rangeRt, + comparisonRangeRt, uiFiltersRt, t.type({ transactionNames: jsonRt, @@ -137,10 +140,14 @@ export const transactionGroupsComparisonStatisticsRoute = createRoute({ latencyAggregationType, numBuckets, transactionType, + comparisonStart, + comparisonEnd, }, } = context.params; - return getServiceTransactionGroupComparisonStatistics({ + const { start, end } = setup; + + const commomProps = { setup, serviceName, transactionNames, @@ -148,7 +155,54 @@ export const transactionGroupsComparisonStatisticsRoute = createRoute({ transactionType, numBuckets, latencyAggregationType: latencyAggregationType as LatencyAggregationType, - }); + }; + + const previousPeriodPromise = + comparisonStart && comparisonEnd + ? getServiceTransactionGroupComparisonStatistics({ + ...commomProps, + start: comparisonStart, + end: comparisonEnd, + }).then((previousStatistics) => { + return previousStatistics.map( + ({ transactionName, errorRate, throughput, latency, impact }) => { + return { + transactionName, + impact, + errorRate: offsetPreviousPeriodCoordinates({ + currentPeriodStart: start, + previousPeriodStart: comparisonStart, + previousPeriodTimeseries: errorRate, + }), + throughput: offsetPreviousPeriodCoordinates({ + currentPeriodStart: start, + previousPeriodStart: comparisonStart, + previousPeriodTimeseries: throughput, + }), + latency: offsetPreviousPeriodCoordinates({ + currentPeriodStart: start, + previousPeriodStart: comparisonStart, + previousPeriodTimeseries: latency, + }), + }; + } + ); + }) + : []; + + const [currentPeriod, previousPeriod] = await Promise.all([ + getServiceTransactionGroupComparisonStatistics({ + ...commomProps, + start, + end, + }), + previousPeriodPromise, + ]); + + return { + currentPeriod: keyBy(currentPeriod, 'transactionName'), + previousPeriod: keyBy(previousPeriod, 'transactionName'), + }; }, }); From 6434cc0f92b608ebb160f28abcb042a55d8c0a5c Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Mon, 15 Feb 2021 13:23:29 -0500 Subject: [PATCH 02/13] fixing api test --- .../get_columns.tsx | 8 +- .../charts/comparison_spark_plot/index.tsx | 99 +++++ .../shared/charts/spark_plot/index.tsx | 25 +- ...transaction_group_comparison_statistics.ts | 86 +++- .../plugins/apm/server/routes/transactions.ts | 59 +-- ...sactions_groups_comparison_statistics.snap | 416 +++++++++++++++++- ...ansactions_groups_comparison_statistics.ts | 104 ++++- 7 files changed, 699 insertions(+), 98 deletions(-) create mode 100644 x-pack/plugins/apm/public/components/shared/charts/comparison_spark_plot/index.tsx diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx index 82cfac5364ce5..add7ff0812509 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx @@ -16,7 +16,7 @@ import { } from '../../../../../common/utils/formatters'; import { APIReturnType } from '../../../../services/rest/createCallApmApi'; import { px, unit } from '../../../../style/variables'; -import { SparkPlot } from '../../../shared/charts/spark_plot'; +import { ComparisonSparkPlot } from '../../../shared/charts/comparison_spark_plot'; import { ImpactBar } from '../../../shared/ImpactBar'; import { TransactionDetailLink } from '../../../shared/Links/apm/transaction_detail_link'; import { TruncateWithTooltip } from '../../../shared/truncate_with_tooltip'; @@ -98,7 +98,7 @@ export function getColumns({ const previousTimeseries = transactionGroupComparisonStatistics?.previousPeriod?.[name]?.latency; return ( - + + {!series || series.every((point) => point.y === null) ? ( + + ) : ( + + + + + + )} + + + {valueLabel} + + + ); +} diff --git a/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx index 2336a547d4f01..0944b312eabd0 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx @@ -12,7 +12,6 @@ import { AreaSeries, Chart, CurveType, - LineSeries, ScaleType, Settings, } from '@elastic/charts'; @@ -21,9 +20,8 @@ import { Coordinate } from '../../../../../typings/timeseries'; import { useChartTheme } from '../../../../../../observability/public'; import { px, unit } from '../../../../style/variables'; import { useTheme } from '../../../../hooks/use_theme'; -import { getComparisonChartTheme } from '../../time_comparison/get_time_range_comparison'; -type Color = +export type Color = | 'euiColorVis0' | 'euiColorVis1' | 'euiColorVis2' @@ -40,24 +38,23 @@ export function SparkPlot({ series, valueLabel, compact, - comparisonSeries = [], }: { color: Color; series?: Coordinate[] | null; valueLabel: React.ReactNode; compact?: boolean; - comparisonSeries?: Coordinate[]; }) { const theme = useTheme(); const defaultChartTheme = useChartTheme(); - const comparisonChartTheme = getComparisonChartTheme(theme); const sparkplotChartTheme = merge({}, defaultChartTheme, { chartMargins: { left: 0, right: 0, top: 0, bottom: 0 }, lineSeriesStyle: { point: { opacity: 0 }, }, - ...comparisonChartTheme, + areaSeriesStyle: { + point: { opacity: 0 }, + }, }); const colorValue = theme.eui[color]; @@ -79,24 +76,14 @@ export function SparkPlot({ showLegend={false} tooltip="none" /> - diff --git a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts index 6086e855bcf68..70fb1a63bf2db 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts @@ -16,6 +16,7 @@ import { EventOutcome } from '../../../common/event_outcome'; import { LatencyAggregationType } from '../../../common/latency_aggregation_types'; import { rangeFilter } from '../../../common/utils/range_filter'; import { Coordinate } from '../../../typings/timeseries'; +import { offsetPreviousPeriodCoordinates } from '../../utils/offset_previous_period_coordinate'; import { withApmSpan } from '../../utils/with_apm_span'; import { getDocumentTypeFilterForAggregatedTransactions, @@ -27,7 +28,7 @@ import { getLatencyAggregation, getLatencyValue, } from '../helpers/latency_aggregation_type'; -import { Setup } from '../helpers/setup_request'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { calculateTransactionErrorPercentage } from '../helpers/transaction_error_rate'; export async function getServiceTransactionGroupComparisonStatistics({ @@ -174,3 +175,86 @@ export async function getServiceTransactionGroupComparisonStatistics({ } ); } + +export async function getServiceTransactionGroupComparisonStatisticsPeriods({ + serviceName, + transactionNames, + setup, + numBuckets, + searchAggregatedTransactions, + transactionType, + latencyAggregationType, + comparisonStart, + comparisonEnd, +}: { + serviceName: string; + transactionNames: string[]; + setup: Setup & SetupTimeRange; + numBuckets: number; + searchAggregatedTransactions: boolean; + transactionType: string; + latencyAggregationType: LatencyAggregationType; + comparisonStart?: number; + comparisonEnd?: number; +}) { + const { start, end } = setup; + + const commomProps = { + setup, + serviceName, + transactionNames, + searchAggregatedTransactions, + transactionType, + numBuckets, + latencyAggregationType: latencyAggregationType as LatencyAggregationType, + }; + + const currentPeriodPromise = getServiceTransactionGroupComparisonStatistics({ + ...commomProps, + start, + end, + }); + + const previousPeriodPromise = + comparisonStart && comparisonEnd + ? getServiceTransactionGroupComparisonStatistics({ + ...commomProps, + start: comparisonStart, + end: comparisonEnd, + }).then((previousStatistics) => { + return previousStatistics.map( + ({ transactionName, errorRate, throughput, latency, impact }) => { + return { + transactionName, + impact, + errorRate: offsetPreviousPeriodCoordinates({ + currentPeriodStart: start, + previousPeriodStart: comparisonStart, + previousPeriodTimeseries: errorRate, + }), + throughput: offsetPreviousPeriodCoordinates({ + currentPeriodStart: start, + previousPeriodStart: comparisonStart, + previousPeriodTimeseries: throughput, + }), + latency: offsetPreviousPeriodCoordinates({ + currentPeriodStart: start, + previousPeriodStart: comparisonStart, + previousPeriodTimeseries: latency, + }), + }; + } + ); + }) + : []; + + const [currentPeriod, previousPeriod] = await Promise.all([ + currentPeriodPromise, + previousPeriodPromise, + ]); + + return { + currentPeriod: keyBy(currentPeriod, 'transactionName'), + previousPeriod: keyBy(previousPeriod, 'transactionName'), + }; +} diff --git a/x-pack/plugins/apm/server/routes/transactions.ts b/x-pack/plugins/apm/server/routes/transactions.ts index 575bc46d7892e..8e62ca1f2cbf5 100644 --- a/x-pack/plugins/apm/server/routes/transactions.ts +++ b/x-pack/plugins/apm/server/routes/transactions.ts @@ -7,7 +7,6 @@ import Boom from '@hapi/boom'; import * as t from 'io-ts'; -import { keyBy } from 'lodash'; import { LatencyAggregationType, latencyAggregationTypeRt, @@ -17,7 +16,7 @@ import { toNumberRt } from '../../common/runtime_types/to_number_rt'; import { getSearchAggregatedTransactions } from '../lib/helpers/aggregated_transactions'; import { setupRequest } from '../lib/helpers/setup_request'; import { getServiceTransactionGroups } from '../lib/services/get_service_transaction_groups'; -import { getServiceTransactionGroupComparisonStatistics } from '../lib/services/get_service_transaction_group_comparison_statistics'; +import { getServiceTransactionGroupComparisonStatisticsPeriods } from '../lib/services/get_service_transaction_group_comparison_statistics'; import { getTransactionBreakdown } from '../lib/transactions/breakdown'; import { getTransactionDistribution } from '../lib/transactions/distribution'; import { getAnomalySeries } from '../lib/transactions/get_anomaly_data'; @@ -25,7 +24,6 @@ import { getLatencyTimeseries } from '../lib/transactions/get_latency_charts'; import { getThroughputCharts } from '../lib/transactions/get_throughput_charts'; import { getTransactionGroupList } from '../lib/transaction_groups'; import { getErrorRate } from '../lib/transaction_groups/get_error_rate'; -import { offsetPreviousPeriodCoordinates } from '../utils/offset_previous_period_coordinate'; import { createRoute } from './create_route'; import { comparisonRangeRt, rangeRt, uiFiltersRt } from './default_api_types'; @@ -145,9 +143,7 @@ export const transactionGroupsComparisonStatisticsRoute = createRoute({ }, } = context.params; - const { start, end } = setup; - - const commomProps = { + return getServiceTransactionGroupComparisonStatisticsPeriods({ setup, serviceName, transactionNames, @@ -155,54 +151,9 @@ export const transactionGroupsComparisonStatisticsRoute = createRoute({ transactionType, numBuckets, latencyAggregationType: latencyAggregationType as LatencyAggregationType, - }; - - const previousPeriodPromise = - comparisonStart && comparisonEnd - ? getServiceTransactionGroupComparisonStatistics({ - ...commomProps, - start: comparisonStart, - end: comparisonEnd, - }).then((previousStatistics) => { - return previousStatistics.map( - ({ transactionName, errorRate, throughput, latency, impact }) => { - return { - transactionName, - impact, - errorRate: offsetPreviousPeriodCoordinates({ - currentPeriodStart: start, - previousPeriodStart: comparisonStart, - previousPeriodTimeseries: errorRate, - }), - throughput: offsetPreviousPeriodCoordinates({ - currentPeriodStart: start, - previousPeriodStart: comparisonStart, - previousPeriodTimeseries: throughput, - }), - latency: offsetPreviousPeriodCoordinates({ - currentPeriodStart: start, - previousPeriodStart: comparisonStart, - previousPeriodTimeseries: latency, - }), - }; - } - ); - }) - : []; - - const [currentPeriod, previousPeriod] = await Promise.all([ - getServiceTransactionGroupComparisonStatistics({ - ...commomProps, - start, - end, - }), - previousPeriodPromise, - ]); - - return { - currentPeriod: keyBy(currentPeriod, 'transactionName'), - previousPeriod: keyBy(previousPeriod, 'transactionName'), - }; + comparisonStart, + comparisonEnd, + }); }, }); diff --git a/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/transactions_groups_comparison_statistics.snap b/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/transactions_groups_comparison_statistics.snap index 739ff5a080d76..5b8ca94829988 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/transactions_groups_comparison_statistics.snap +++ b/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/transactions_groups_comparison_statistics.snap @@ -1,5 +1,419 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period 1`] = ` +Array [ + Object { + "x": 1607436720000, + "y": null, + }, + Object { + "x": 1607436780000, + "y": null, + }, + Object { + "x": 1607436840000, + "y": null, + }, + Object { + "x": 1607436900000, + "y": null, + }, + Object { + "x": 1607436960000, + "y": 30501, + }, + Object { + "x": 1607437020000, + "y": null, + }, + Object { + "x": 1607437080000, + "y": null, + }, + Object { + "x": 1607437140000, + "y": null, + }, + Object { + "x": 1607437200000, + "y": 46937.5, + }, + Object { + "x": 1607437260000, + "y": null, + }, + Object { + "x": 1607437320000, + "y": null, + }, + Object { + "x": 1607437380000, + "y": null, + }, + Object { + "x": 1607437440000, + "y": null, + }, + Object { + "x": 1607437500000, + "y": null, + }, + Object { + "x": 1607437560000, + "y": null, + }, + Object { + "x": 1607437620000, + "y": null, + }, +] +`; + +exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period 2`] = ` +Array [ + Object { + "x": 1607436720000, + "y": null, + }, + Object { + "x": 1607436780000, + "y": 69429, + }, + Object { + "x": 1607436840000, + "y": 8071285, + }, + Object { + "x": 1607436900000, + "y": 31949, + }, + Object { + "x": 1607436960000, + "y": null, + }, + Object { + "x": 1607437020000, + "y": 47755, + }, + Object { + "x": 1607437080000, + "y": null, + }, + Object { + "x": 1607437140000, + "y": 35403, + }, + Object { + "x": 1607437200000, + "y": null, + }, + Object { + "x": 1607437260000, + "y": null, + }, + Object { + "x": 1607437320000, + "y": null, + }, + Object { + "x": 1607437380000, + "y": 48137, + }, + Object { + "x": 1607437440000, + "y": null, + }, + Object { + "x": 1607437500000, + "y": 35457, + }, + Object { + "x": 1607437560000, + "y": null, + }, + Object { + "x": 1607437620000, + "y": null, + }, +] +`; + +exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period 3`] = ` +Array [ + Object { + "x": 1607436720000, + "y": 0, + }, + Object { + "x": 1607436780000, + "y": 0, + }, + Object { + "x": 1607436840000, + "y": 0, + }, + Object { + "x": 1607436900000, + "y": 0, + }, + Object { + "x": 1607436960000, + "y": 2, + }, + Object { + "x": 1607437020000, + "y": 0, + }, + Object { + "x": 1607437080000, + "y": 0, + }, + Object { + "x": 1607437140000, + "y": 0, + }, + Object { + "x": 1607437200000, + "y": 2, + }, + Object { + "x": 1607437260000, + "y": 0, + }, + Object { + "x": 1607437320000, + "y": 0, + }, + Object { + "x": 1607437380000, + "y": 0, + }, + Object { + "x": 1607437440000, + "y": 0, + }, + Object { + "x": 1607437500000, + "y": 0, + }, + Object { + "x": 1607437560000, + "y": 0, + }, + Object { + "x": 1607437620000, + "y": 0, + }, +] +`; + +exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period 4`] = ` +Array [ + Object { + "x": 1607436720000, + "y": 0, + }, + Object { + "x": 1607436780000, + "y": 1, + }, + Object { + "x": 1607436840000, + "y": 2, + }, + Object { + "x": 1607436900000, + "y": 1, + }, + Object { + "x": 1607436960000, + "y": 0, + }, + Object { + "x": 1607437020000, + "y": 1, + }, + Object { + "x": 1607437080000, + "y": 0, + }, + Object { + "x": 1607437140000, + "y": 4, + }, + Object { + "x": 1607437200000, + "y": 0, + }, + Object { + "x": 1607437260000, + "y": 0, + }, + Object { + "x": 1607437320000, + "y": 0, + }, + Object { + "x": 1607437380000, + "y": 2, + }, + Object { + "x": 1607437440000, + "y": 0, + }, + Object { + "x": 1607437500000, + "y": 1, + }, + Object { + "x": 1607437560000, + "y": 0, + }, + Object { + "x": 1607437620000, + "y": 0, + }, +] +`; + +exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period 5`] = ` +Array [ + Object { + "x": 1607436720000, + "y": null, + }, + Object { + "x": 1607436780000, + "y": null, + }, + Object { + "x": 1607436840000, + "y": null, + }, + Object { + "x": 1607436900000, + "y": null, + }, + Object { + "x": 1607436960000, + "y": 0, + }, + Object { + "x": 1607437020000, + "y": null, + }, + Object { + "x": 1607437080000, + "y": null, + }, + Object { + "x": 1607437140000, + "y": null, + }, + Object { + "x": 1607437200000, + "y": 0.5, + }, + Object { + "x": 1607437260000, + "y": null, + }, + Object { + "x": 1607437320000, + "y": null, + }, + Object { + "x": 1607437380000, + "y": null, + }, + Object { + "x": 1607437440000, + "y": null, + }, + Object { + "x": 1607437500000, + "y": null, + }, + Object { + "x": 1607437560000, + "y": null, + }, + Object { + "x": 1607437620000, + "y": null, + }, +] +`; + +exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period 6`] = ` +Array [ + Object { + "x": 1607436720000, + "y": null, + }, + Object { + "x": 1607436780000, + "y": 0, + }, + Object { + "x": 1607436840000, + "y": 0, + }, + Object { + "x": 1607436900000, + "y": 0, + }, + Object { + "x": 1607436960000, + "y": null, + }, + Object { + "x": 1607437020000, + "y": 0, + }, + Object { + "x": 1607437080000, + "y": null, + }, + Object { + "x": 1607437140000, + "y": 0, + }, + Object { + "x": 1607437200000, + "y": null, + }, + Object { + "x": 1607437260000, + "y": null, + }, + Object { + "x": 1607437320000, + "y": null, + }, + Object { + "x": 1607437380000, + "y": 0, + }, + Object { + "x": 1607437440000, + "y": null, + }, + Object { + "x": 1607437500000, + "y": 0, + }, + Object { + "x": 1607437560000, + "y": null, + }, + Object { + "x": 1607437620000, + "y": null, + }, +] +`; + exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns the correct data 1`] = ` Array [ Object { @@ -387,7 +801,7 @@ Array [ ] `; -exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns the correct for latency aggregation 99th percentile 1`] = ` +exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns the correct data for latency aggregation 99th percentile 1`] = ` Array [ Object { "x": 1607435820000, diff --git a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts index 414e2189a63fe..759900650b3f4 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts @@ -7,6 +7,7 @@ import expect from '@kbn/expect'; import url from 'url'; +import moment from 'moment'; import { APIReturnType } from '../../../../plugins/apm/public/services/rest/createCallApmApi'; import archives from '../../common/fixtures/es_archiver/archives_metadata'; import { FtrProviderContext } from '../../common/ftr_provider_context'; @@ -43,7 +44,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { ); expect(response.status).to.be(200); - expect(response.body).to.empty(); + expect(response.body).to.be.eql({ currentPeriod: {}, previousPeriod: {} }); }); } ); @@ -70,19 +71,19 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(response.status).to.be(200); - const transactionsGroupsComparisonStatistics = response.body as TransactionsGroupsComparisonStatistics; + const { + currentPeriod, + previousPeriod, + } = response.body as TransactionsGroupsComparisonStatistics; - expect(Object.keys(transactionsGroupsComparisonStatistics).length).to.be.eql( - transactionNames.length - ); + expect(Object.keys(currentPeriod).length).to.be.eql(transactionNames.length); + expect(Object.keys(previousPeriod).length).to.be.eql(0); transactionNames.map((transactionName) => { - expect(transactionsGroupsComparisonStatistics[transactionName]).not.to.be.empty(); + expect(currentPeriod[transactionName]).not.to.be.empty(); }); - const { latency, throughput, errorRate, impact } = transactionsGroupsComparisonStatistics[ - transactionNames[0] - ]; + const { latency, throughput, errorRate, impact } = currentPeriod[transactionNames[0]]; expect(removeEmptyCoordinates(latency).length).to.be.greaterThan(0); expectSnapshot(latency).toMatch(); @@ -96,7 +97,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { expectSnapshot(roundNumber(impact)).toMatchInline(`"93.93"`); }); - it('returns the correct for latency aggregation 99th percentile', async () => { + it('returns the correct data for latency aggregation 99th percentile', async () => { const response = await supertest.get( url.format({ pathname: `/api/apm/services/opbeans-java/transactions/groups/comparison_statistics`, @@ -114,19 +115,19 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(response.status).to.be(200); - const transactionsGroupsComparisonStatistics = response.body as TransactionsGroupsComparisonStatistics; + const { + currentPeriod, + previousPeriod, + } = response.body as TransactionsGroupsComparisonStatistics; - expect(Object.keys(transactionsGroupsComparisonStatistics).length).to.be.eql( - transactionNames.length - ); + expect(Object.keys(currentPeriod).length).to.be.eql(transactionNames.length); + expect(Object.keys(previousPeriod).length).to.be.eql(0); transactionNames.map((transactionName) => { - expect(transactionsGroupsComparisonStatistics[transactionName]).not.to.be.empty(); + expect(currentPeriod[transactionName]).not.to.be.empty(); }); - const { latency, throughput, errorRate } = transactionsGroupsComparisonStatistics[ - transactionNames[0] - ]; + const { latency, throughput, errorRate } = currentPeriod[transactionNames[0]]; expect(removeEmptyCoordinates(latency).length).to.be.greaterThan(0); expectSnapshot(latency).toMatch(); @@ -151,7 +152,72 @@ export default function ApiTest({ getService }: FtrProviderContext) { ); expect(response.status).to.be(200); - expect(response.body).to.empty(); + expect(response.body).to.be.eql({ currentPeriod: {}, previousPeriod: {} }); + }); + + it('returns data with previous period', async () => { + const response = await supertest.get( + url.format({ + pathname: `/api/apm/services/opbeans-java/transactions/groups/comparison_statistics`, + query: { + uiFilters: '{}', + numBuckets: 20, + transactionType: 'request', + latencyAggregationType: 'avg', + transactionNames: JSON.stringify(transactionNames), + start: moment(end).subtract(15, 'minutes').toISOString(), + end, + comparisonStart: start, + comparisonEnd: moment(start).add(15, 'minutes').toISOString(), + }, + }) + ); + + expect(response.status).to.be(200); + + const { + currentPeriod, + previousPeriod, + } = response.body as TransactionsGroupsComparisonStatistics; + + expect(Object.keys(currentPeriod).length).to.be.eql(transactionNames.length); + expect(Object.keys(previousPeriod).length).to.be.eql(transactionNames.length); + + transactionNames.map((transactionName) => { + expect(currentPeriod[transactionName]).not.to.be.empty(); + expect(previousPeriod[transactionName]).not.to.be.empty(); + }); + + const currentPeriodStatistics = currentPeriod[transactionNames[0]]; + const previousPeriodStatistics = previousPeriod[transactionNames[0]]; + + expect(removeEmptyCoordinates(currentPeriodStatistics.latency).length).to.be.greaterThan(0); + expect(removeEmptyCoordinates(previousPeriodStatistics.latency).length).to.be.greaterThan( + 0 + ); + expectSnapshot(currentPeriodStatistics.latency).toMatch(); + expectSnapshot(previousPeriodStatistics.latency).toMatch(); + + expect(removeEmptyCoordinates(currentPeriodStatistics.throughput).length).to.be.greaterThan( + 0 + ); + expect( + removeEmptyCoordinates(previousPeriodStatistics.throughput).length + ).to.be.greaterThan(0); + expectSnapshot(currentPeriodStatistics.throughput).toMatch(); + expectSnapshot(previousPeriodStatistics.throughput).toMatch(); + + expect(removeEmptyCoordinates(currentPeriodStatistics.errorRate).length).to.be.greaterThan( + 0 + ); + expect(removeEmptyCoordinates(previousPeriodStatistics.errorRate).length).to.be.greaterThan( + 0 + ); + expectSnapshot(currentPeriodStatistics.errorRate).toMatch(); + expectSnapshot(previousPeriodStatistics.errorRate).toMatch(); + + expectSnapshot(roundNumber(currentPeriodStatistics.impact)).toMatchInline(`"21.75"`); + expectSnapshot(roundNumber(previousPeriodStatistics.impact)).toMatchInline(`"96.94"`); }); } ); From 720ff4664b15ecf0d982aa3fa0c9669e39327e2e Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Thu, 18 Feb 2021 15:49:52 -0500 Subject: [PATCH 03/13] merge --- .../get_service_transaction_group_comparison_statistics.ts | 3 +++ x-pack/plugins/apm/server/routes/transactions.ts | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts index 4ad7098ae128a..d5aa16fd439cb 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts @@ -189,6 +189,7 @@ export async function getServiceTransactionGroupComparisonStatisticsPeriods({ latencyAggregationType, comparisonStart, comparisonEnd, + environment, }: { serviceName: string; transactionNames: string[]; @@ -199,6 +200,7 @@ export async function getServiceTransactionGroupComparisonStatisticsPeriods({ latencyAggregationType: LatencyAggregationType; comparisonStart?: number; comparisonEnd?: number; + environment?: string; }) { const { start, end } = setup; @@ -210,6 +212,7 @@ export async function getServiceTransactionGroupComparisonStatisticsPeriods({ transactionType, numBuckets, latencyAggregationType: latencyAggregationType as LatencyAggregationType, + environment, }; const currentPeriodPromise = getServiceTransactionGroupComparisonStatistics({ diff --git a/x-pack/plugins/apm/server/routes/transactions.ts b/x-pack/plugins/apm/server/routes/transactions.ts index cdf10fabb24ef..e172b46e481b5 100644 --- a/x-pack/plugins/apm/server/routes/transactions.ts +++ b/x-pack/plugins/apm/server/routes/transactions.ts @@ -153,7 +153,7 @@ export const transactionGroupsComparisonStatisticsRoute = createRoute({ }, } = context.params; - return getServiceTransactionGroupComparisonStatisticsPeriods({ + return await getServiceTransactionGroupComparisonStatisticsPeriods({ environment, setup, serviceName, From 9aeb9efa83707de26b2111077acd2fe997ec2673 Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Tue, 23 Feb 2021 14:05:55 -0500 Subject: [PATCH 04/13] addressing PR comments --- .../components/app/service_overview/index.tsx | 6 +- .../get_columns.tsx | 10 +- .../charts/comparison_spark_plot/index.tsx | 99 ---------- .../shared/charts/spark_plot/index.tsx | 31 ++- ...sactions_groups_comparison_statistics.snap | 158 +++++++-------- ...ansactions_groups_comparison_statistics.ts | 181 ++++++++++++------ 6 files changed, 236 insertions(+), 249 deletions(-) delete mode 100644 x-pack/plugins/apm/public/components/shared/charts/comparison_spark_plot/index.tsx diff --git a/x-pack/plugins/apm/public/components/app/service_overview/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx index a0ea00ae5c3ad..f6ec2fb24018f 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx @@ -57,7 +57,11 @@ export function ServiceOverview({ return ( - + diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx index 5d4545fd09206..30dc138e829eb 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx @@ -17,7 +17,7 @@ import { } from '../../../../../common/utils/formatters'; import { APIReturnType } from '../../../../services/rest/createCallApmApi'; import { px, unit } from '../../../../style/variables'; -import { ComparisonSparkPlot } from '../../../shared/charts/comparison_spark_plot'; +import { SparkPlot } from '../../../shared/charts/spark_plot'; import { ImpactBar } from '../../../shared/ImpactBar'; import { TransactionDetailLink } from '../../../shared/Links/apm/transaction_detail_link'; import { TruncateWithTooltip } from '../../../shared/truncate_with_tooltip'; @@ -34,7 +34,7 @@ export function getColumns({ serviceName, latencyAggregationType, transactionGroupComparisonStatistics, - comparisonEnabled = true, + comparisonEnabled, }: { serviceName: string; latencyAggregationType?: LatencyAggregationType; @@ -78,7 +78,7 @@ export function getColumns({ const previousTimeseries = transactionGroupComparisonStatistics?.previousPeriod?.[name]?.latency; return ( - - - {!series || series.every((point) => point.y === null) ? ( - - ) : ( - - - - - - )} - - - {valueLabel} - - - ); -} diff --git a/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx index 0944b312eabd0..e885a3cb00fd9 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx @@ -12,6 +12,7 @@ import { AreaSeries, Chart, CurveType, + LineSeries, ScaleType, Settings, } from '@elastic/charts'; @@ -20,6 +21,7 @@ import { Coordinate } from '../../../../../typings/timeseries'; import { useChartTheme } from '../../../../../../observability/public'; import { px, unit } from '../../../../style/variables'; import { useTheme } from '../../../../hooks/use_theme'; +import { getComparisonChartTheme } from '../../time_comparison/get_time_range_comparison'; export type Color = | 'euiColorVis0' @@ -33,9 +35,14 @@ export type Color = | 'euiColorVis8' | 'euiColorVis9'; +function isEmptyTimeseries(series: Coordinate[]) { + return series.every((point) => point.y === null); +} + export function SparkPlot({ color, series, + comparisonSeries = [], valueLabel, compact, }: { @@ -43,9 +50,12 @@ export function SparkPlot({ series?: Coordinate[] | null; valueLabel: React.ReactNode; compact?: boolean; + comparisonSeries?: Coordinate[]; }) { const theme = useTheme(); const defaultChartTheme = useChartTheme(); + const comparisonChartTheme = getComparisonChartTheme(theme); + const hasComparisonSeries = !!comparisonSeries?.length; const sparkplotChartTheme = merge({}, defaultChartTheme, { chartMargins: { left: 0, right: 0, top: 0, bottom: 0 }, @@ -55,6 +65,7 @@ export function SparkPlot({ areaSeriesStyle: { point: { opacity: 0 }, }, + ...(hasComparisonSeries ? comparisonChartTheme : {}), }); const colorValue = theme.eui[color]; @@ -64,10 +75,12 @@ export function SparkPlot({ width: compact ? px(unit * 3) : px(unit * 4), }; + const SparklinesSeries = hasComparisonSeries ? LineSeries : AreaSeries; + return ( - {!series || series.every((point) => point.y === null) ? ( + {!series || isEmptyTimeseries(series) ? ( ) : ( @@ -76,8 +89,8 @@ export function SparkPlot({ showLegend={false} tooltip="none" /> - + {hasComparisonSeries && ( + + )} )} diff --git a/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/transactions_groups_comparison_statistics.snap b/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/transactions_groups_comparison_statistics.snap index 5b8ca94829988..bc641ad1a9890 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/transactions_groups_comparison_statistics.snap +++ b/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/transactions_groups_comparison_statistics.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period 1`] = ` +exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period returns correct error rate data 1`] = ` Array [ Object { "x": 1607436720000, @@ -20,7 +20,7 @@ Array [ }, Object { "x": 1607436960000, - "y": 30501, + "y": 0, }, Object { "x": 1607437020000, @@ -36,7 +36,7 @@ Array [ }, Object { "x": 1607437200000, - "y": 46937.5, + "y": 0.5, }, Object { "x": 1607437260000, @@ -69,7 +69,7 @@ Array [ ] `; -exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period 2`] = ` +exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period returns correct error rate data 2`] = ` Array [ Object { "x": 1607436720000, @@ -77,15 +77,15 @@ Array [ }, Object { "x": 1607436780000, - "y": 69429, + "y": 0, }, Object { "x": 1607436840000, - "y": 8071285, + "y": 0, }, Object { "x": 1607436900000, - "y": 31949, + "y": 0, }, Object { "x": 1607436960000, @@ -93,7 +93,7 @@ Array [ }, Object { "x": 1607437020000, - "y": 47755, + "y": 0, }, Object { "x": 1607437080000, @@ -101,7 +101,7 @@ Array [ }, Object { "x": 1607437140000, - "y": 35403, + "y": 0, }, Object { "x": 1607437200000, @@ -117,7 +117,7 @@ Array [ }, Object { "x": 1607437380000, - "y": 48137, + "y": 0, }, Object { "x": 1607437440000, @@ -125,7 +125,7 @@ Array [ }, Object { "x": 1607437500000, - "y": 35457, + "y": 0, }, Object { "x": 1607437560000, @@ -138,278 +138,278 @@ Array [ ] `; -exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period 3`] = ` +exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period returns correct latency data 1`] = ` Array [ Object { "x": 1607436720000, - "y": 0, + "y": null, }, Object { "x": 1607436780000, - "y": 0, + "y": null, }, Object { "x": 1607436840000, - "y": 0, + "y": null, }, Object { "x": 1607436900000, - "y": 0, + "y": null, }, Object { "x": 1607436960000, - "y": 2, + "y": 30501, }, Object { "x": 1607437020000, - "y": 0, + "y": null, }, Object { "x": 1607437080000, - "y": 0, + "y": null, }, Object { "x": 1607437140000, - "y": 0, + "y": null, }, Object { "x": 1607437200000, - "y": 2, + "y": 46937.5, }, Object { "x": 1607437260000, - "y": 0, + "y": null, }, Object { "x": 1607437320000, - "y": 0, + "y": null, }, Object { "x": 1607437380000, - "y": 0, + "y": null, }, Object { "x": 1607437440000, - "y": 0, + "y": null, }, Object { "x": 1607437500000, - "y": 0, + "y": null, }, Object { "x": 1607437560000, - "y": 0, + "y": null, }, Object { "x": 1607437620000, - "y": 0, + "y": null, }, ] `; -exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period 4`] = ` +exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period returns correct latency data 2`] = ` Array [ Object { "x": 1607436720000, - "y": 0, + "y": null, }, Object { "x": 1607436780000, - "y": 1, + "y": 69429, }, Object { "x": 1607436840000, - "y": 2, + "y": 8071285, }, Object { "x": 1607436900000, - "y": 1, + "y": 31949, }, Object { "x": 1607436960000, - "y": 0, + "y": null, }, Object { "x": 1607437020000, - "y": 1, + "y": 47755, }, Object { "x": 1607437080000, - "y": 0, + "y": null, }, Object { "x": 1607437140000, - "y": 4, + "y": 35403, }, Object { "x": 1607437200000, - "y": 0, + "y": null, }, Object { "x": 1607437260000, - "y": 0, + "y": null, }, Object { "x": 1607437320000, - "y": 0, + "y": null, }, Object { "x": 1607437380000, - "y": 2, + "y": 48137, }, Object { "x": 1607437440000, - "y": 0, + "y": null, }, Object { "x": 1607437500000, - "y": 1, + "y": 35457, }, Object { "x": 1607437560000, - "y": 0, + "y": null, }, Object { "x": 1607437620000, - "y": 0, + "y": null, }, ] `; -exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period 5`] = ` +exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period returns correct throughput data 1`] = ` Array [ Object { "x": 1607436720000, - "y": null, + "y": 0, }, Object { "x": 1607436780000, - "y": null, + "y": 0, }, Object { "x": 1607436840000, - "y": null, + "y": 0, }, Object { "x": 1607436900000, - "y": null, + "y": 0, }, Object { "x": 1607436960000, - "y": 0, + "y": 2, }, Object { "x": 1607437020000, - "y": null, + "y": 0, }, Object { "x": 1607437080000, - "y": null, + "y": 0, }, Object { "x": 1607437140000, - "y": null, + "y": 0, }, Object { "x": 1607437200000, - "y": 0.5, + "y": 2, }, Object { "x": 1607437260000, - "y": null, + "y": 0, }, Object { "x": 1607437320000, - "y": null, + "y": 0, }, Object { "x": 1607437380000, - "y": null, + "y": 0, }, Object { "x": 1607437440000, - "y": null, + "y": 0, }, Object { "x": 1607437500000, - "y": null, + "y": 0, }, Object { "x": 1607437560000, - "y": null, + "y": 0, }, Object { "x": 1607437620000, - "y": null, + "y": 0, }, ] `; -exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period 6`] = ` +exports[`APM API tests basic apm_8.0.0 Transaction groups comparison statistics when data is loaded returns data with previous period returns correct throughput data 2`] = ` Array [ Object { "x": 1607436720000, - "y": null, + "y": 0, }, Object { "x": 1607436780000, - "y": 0, + "y": 1, }, Object { "x": 1607436840000, - "y": 0, + "y": 2, }, Object { "x": 1607436900000, - "y": 0, + "y": 1, }, Object { "x": 1607436960000, - "y": null, + "y": 0, }, Object { "x": 1607437020000, - "y": 0, + "y": 1, }, Object { "x": 1607437080000, - "y": null, + "y": 0, }, Object { "x": 1607437140000, - "y": 0, + "y": 4, }, Object { "x": 1607437200000, - "y": null, + "y": 0, }, Object { "x": 1607437260000, - "y": null, + "y": 0, }, Object { "x": 1607437320000, - "y": null, + "y": 0, }, Object { "x": 1607437380000, - "y": 0, + "y": 2, }, Object { "x": 1607437440000, - "y": null, + "y": 0, }, Object { "x": 1607437500000, - "y": 0, + "y": 1, }, Object { "x": 1607437560000, - "y": null, + "y": 0, }, Object { "x": 1607437620000, - "y": null, + "y": 0, }, ] `; diff --git a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts index 759900650b3f4..3399cf22a7fb4 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts @@ -8,6 +8,7 @@ import expect from '@kbn/expect'; import url from 'url'; import moment from 'moment'; +import { pick } from 'lodash'; import { APIReturnType } from '../../../../plugins/apm/public/services/rest/createCallApmApi'; import archives from '../../common/fixtures/es_archiver/archives_metadata'; import { FtrProviderContext } from '../../common/ftr_provider_context'; @@ -76,14 +77,25 @@ export default function ApiTest({ getService }: FtrProviderContext) { previousPeriod, } = response.body as TransactionsGroupsComparisonStatistics; - expect(Object.keys(currentPeriod).length).to.be.eql(transactionNames.length); - expect(Object.keys(previousPeriod).length).to.be.eql(0); + expect(Object.keys(currentPeriod)).to.be.eql(transactionNames); - transactionNames.map((transactionName) => { + const currentPeriodItems = Object.values(currentPeriod).map((data) => data); + const previousPeriodItems = Object.values(previousPeriod).map((data) => data); + + expect(previousPeriodItems.length).to.be.eql(0); + + transactionNames.forEach((transactionName) => { expect(currentPeriod[transactionName]).not.to.be.empty(); }); - const { latency, throughput, errorRate, impact } = currentPeriod[transactionNames[0]]; + const firstItem = currentPeriodItems[0]; + const { latency, throughput, errorRate, impact } = pick( + firstItem, + 'latency', + 'throughput', + 'errorRate', + 'impact' + ); expect(removeEmptyCoordinates(latency).length).to.be.greaterThan(0); expectSnapshot(latency).toMatch(); @@ -120,14 +132,25 @@ export default function ApiTest({ getService }: FtrProviderContext) { previousPeriod, } = response.body as TransactionsGroupsComparisonStatistics; - expect(Object.keys(currentPeriod).length).to.be.eql(transactionNames.length); - expect(Object.keys(previousPeriod).length).to.be.eql(0); + expect(Object.keys(currentPeriod)).to.be.eql(transactionNames); + + const currentPeriodItems = Object.values(currentPeriod).map((data) => data); + const previousPeriodItems = Object.values(previousPeriod).map((data) => data); + + expect(previousPeriodItems).to.be.empty(); - transactionNames.map((transactionName) => { + transactionNames.forEach((transactionName) => { expect(currentPeriod[transactionName]).not.to.be.empty(); }); - const { latency, throughput, errorRate } = currentPeriod[transactionNames[0]]; + const firstItem = currentPeriodItems[0]; + const { latency, throughput, errorRate } = pick( + firstItem, + 'latency', + 'throughput', + 'errorRate' + ); + expect(removeEmptyCoordinates(latency).length).to.be.greaterThan(0); expectSnapshot(latency).toMatch(); @@ -155,69 +178,103 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(response.body).to.be.eql({ currentPeriod: {}, previousPeriod: {} }); }); - it('returns data with previous period', async () => { - const response = await supertest.get( - url.format({ - pathname: `/api/apm/services/opbeans-java/transactions/groups/comparison_statistics`, - query: { - uiFilters: '{}', - numBuckets: 20, - transactionType: 'request', - latencyAggregationType: 'avg', - transactionNames: JSON.stringify(transactionNames), - start: moment(end).subtract(15, 'minutes').toISOString(), - end, - comparisonStart: start, - comparisonEnd: moment(start).add(15, 'minutes').toISOString(), - }, - }) - ); + describe('returns data with previous period', async () => { + let currentPeriod: TransactionsGroupsComparisonStatistics['currentPeriod']; + let previousPeriod: TransactionsGroupsComparisonStatistics['previousPeriod']; + before(async () => { + const response = await supertest.get( + url.format({ + pathname: `/api/apm/services/opbeans-java/transactions/groups/comparison_statistics`, + query: { + uiFilters: '{}', + numBuckets: 20, + transactionType: 'request', + latencyAggregationType: 'avg', + transactionNames: JSON.stringify(transactionNames), + start: moment(end).subtract(15, 'minutes').toISOString(), + end, + comparisonStart: start, + comparisonEnd: moment(start).add(15, 'minutes').toISOString(), + }, + }) + ); + + expect(response.status).to.be(200); + currentPeriod = response.body.currentPeriod; + previousPeriod = response.body.previousPeriod; + }); - expect(response.status).to.be(200); + it('returns corrent number of items', () => { + expect(Object.keys(currentPeriod)).to.be.eql(transactionNames); + expect(Object.keys(previousPeriod)).to.be.eql(transactionNames); - const { - currentPeriod, - previousPeriod, - } = response.body as TransactionsGroupsComparisonStatistics; + transactionNames.forEach((transactionName) => { + expect(currentPeriod[transactionName]).not.to.be.empty(); + expect(previousPeriod[transactionName]).not.to.be.empty(); + }); + }); - expect(Object.keys(currentPeriod).length).to.be.eql(transactionNames.length); - expect(Object.keys(previousPeriod).length).to.be.eql(transactionNames.length); + it('returns correct latency data', () => { + const currentPeriodItems = Object.values(currentPeriod).map((data) => data); + const previousPeriodItems = Object.values(previousPeriod).map((data) => data); + + const currentPeriodFirstItem = currentPeriodItems[0]; + const previousPeriodFirstItem = previousPeriodItems[0]; + + expect(removeEmptyCoordinates(currentPeriodFirstItem.latency).length).to.be.greaterThan( + 0 + ); + expect(removeEmptyCoordinates(previousPeriodFirstItem.latency).length).to.be.greaterThan( + 0 + ); + expectSnapshot(currentPeriodFirstItem.latency).toMatch(); + expectSnapshot(previousPeriodFirstItem.latency).toMatch(); + }); - transactionNames.map((transactionName) => { - expect(currentPeriod[transactionName]).not.to.be.empty(); - expect(previousPeriod[transactionName]).not.to.be.empty(); + it('returns correct throughput data', () => { + const currentPeriodItems = Object.values(currentPeriod).map((data) => data); + const previousPeriodItems = Object.values(previousPeriod).map((data) => data); + + const currentPeriodFirstItem = currentPeriodItems[0]; + const previousPeriodFirstItem = previousPeriodItems[0]; + + expect( + removeEmptyCoordinates(currentPeriodFirstItem.throughput).length + ).to.be.greaterThan(0); + expect( + removeEmptyCoordinates(previousPeriodFirstItem.throughput).length + ).to.be.greaterThan(0); + expectSnapshot(currentPeriodFirstItem.throughput).toMatch(); + expectSnapshot(previousPeriodFirstItem.throughput).toMatch(); }); - const currentPeriodStatistics = currentPeriod[transactionNames[0]]; - const previousPeriodStatistics = previousPeriod[transactionNames[0]]; + it('returns correct error rate data', () => { + const currentPeriodItems = Object.values(currentPeriod).map((data) => data); + const previousPeriodItems = Object.values(previousPeriod).map((data) => data); + + const currentPeriodFirstItem = currentPeriodItems[0]; + const previousPeriodFirstItem = previousPeriodItems[0]; + + expect(removeEmptyCoordinates(currentPeriodFirstItem.errorRate).length).to.be.greaterThan( + 0 + ); + expect( + removeEmptyCoordinates(previousPeriodFirstItem.errorRate).length + ).to.be.greaterThan(0); + expectSnapshot(currentPeriodFirstItem.errorRate).toMatch(); + expectSnapshot(previousPeriodFirstItem.errorRate).toMatch(); + }); - expect(removeEmptyCoordinates(currentPeriodStatistics.latency).length).to.be.greaterThan(0); - expect(removeEmptyCoordinates(previousPeriodStatistics.latency).length).to.be.greaterThan( - 0 - ); - expectSnapshot(currentPeriodStatistics.latency).toMatch(); - expectSnapshot(previousPeriodStatistics.latency).toMatch(); + it('returns correct impact data', () => { + const currentPeriodItems = Object.values(currentPeriod).map((data) => data); + const previousPeriodItems = Object.values(previousPeriod).map((data) => data); - expect(removeEmptyCoordinates(currentPeriodStatistics.throughput).length).to.be.greaterThan( - 0 - ); - expect( - removeEmptyCoordinates(previousPeriodStatistics.throughput).length - ).to.be.greaterThan(0); - expectSnapshot(currentPeriodStatistics.throughput).toMatch(); - expectSnapshot(previousPeriodStatistics.throughput).toMatch(); - - expect(removeEmptyCoordinates(currentPeriodStatistics.errorRate).length).to.be.greaterThan( - 0 - ); - expect(removeEmptyCoordinates(previousPeriodStatistics.errorRate).length).to.be.greaterThan( - 0 - ); - expectSnapshot(currentPeriodStatistics.errorRate).toMatch(); - expectSnapshot(previousPeriodStatistics.errorRate).toMatch(); + const currentPeriodFirstItem = currentPeriodItems[0]; + const previousPeriodFirstItem = previousPeriodItems[0]; - expectSnapshot(roundNumber(currentPeriodStatistics.impact)).toMatchInline(`"21.75"`); - expectSnapshot(roundNumber(previousPeriodStatistics.impact)).toMatchInline(`"96.94"`); + expectSnapshot(roundNumber(currentPeriodFirstItem.impact)).toMatchInline(`"21.75"`); + expectSnapshot(roundNumber(previousPeriodFirstItem.impact)).toMatchInline(`"96.94"`); + }); }); } ); From 72477d9042c771ea84e720e39e4293febd424d79 Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Wed, 24 Feb 2021 08:36:41 -0500 Subject: [PATCH 05/13] addressing PR comments --- .../index.tsx | 24 +++++++++---------- .../get_time_range_comparison.ts | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx index ed14af40762f1..25086ea0618be 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx @@ -69,16 +69,11 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { }, } = useUrlParams(); - const { - comparisonStart = undefined, - comparisonEnd = undefined, - } = comparisonType - ? getTimeRangeComparison({ - start, - end, - comparisonType, - }) - : {}; + const { comparisonStart, comparisonEnd } = getTimeRangeComparison({ + start, + end, + comparisonType, + }); const { data = INITIAL_STATE, status } = useFetcher( (callApmApi) => { @@ -101,6 +96,7 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { }, }).then((response) => { return { + // Used to refetch the comparison statistics when a new primary statistics were fetched. requestId: uuid(), ...response, }; @@ -134,6 +130,7 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { } = useFetcher( (callApmApi) => { if ( + status !== FETCH_STATUS.LOADING && currentPageTransactionGroups.length && start && end && @@ -161,9 +158,12 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { }); } }, - // only fetches statistics when requestId, transaction names or comparison range change + // only fetches statistics when requestId, transaction names or comparison type change + // requestId: Is used to refetch the comparison data when a new primary statistics were fetched. + // transactionNams: Is used to fetch the comparison data when a user navigate to a different page within the table + // comparison type: Is used to refetch the comparison when the comparison type is changed, either manually by a user or automatically when the date picker is changed // eslint-disable-next-line react-hooks/exhaustive-deps - [requestId, transactionNames, comparisonStart, comparisonEnd], + [requestId, transactionNames, comparisonType], { preservePreviousData: false } ); diff --git a/x-pack/plugins/apm/public/components/shared/time_comparison/get_time_range_comparison.ts b/x-pack/plugins/apm/public/components/shared/time_comparison/get_time_range_comparison.ts index 5dd014441a9e4..e436f65e85ad9 100644 --- a/x-pack/plugins/apm/public/components/shared/time_comparison/get_time_range_comparison.ts +++ b/x-pack/plugins/apm/public/components/shared/time_comparison/get_time_range_comparison.ts @@ -43,11 +43,11 @@ export function getTimeRangeComparison({ start, end, }: { - comparisonType: TimeRangeComparisonType; + comparisonType?: TimeRangeComparisonType; start?: string; end?: string; }) { - if (!start || !end) { + if (!comparisonType || !start || !end) { return {}; } From 4bcd7c88e8577209bb973996c5923e8773d50f57 Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Wed, 24 Feb 2021 09:03:43 -0500 Subject: [PATCH 06/13] adding kuery filter --- .../get_service_transaction_group_comparison_statistics.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts index 5daaabbfa0d2c..7c6700ab9e773 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts @@ -196,6 +196,7 @@ export async function getServiceTransactionGroupComparisonStatisticsPeriods({ comparisonStart, comparisonEnd, environment, + kuery, }: { serviceName: string; transactionNames: string[]; @@ -207,6 +208,7 @@ export async function getServiceTransactionGroupComparisonStatisticsPeriods({ comparisonStart?: number; comparisonEnd?: number; environment?: string; + kuery?: string; }) { const { start, end } = setup; @@ -219,6 +221,7 @@ export async function getServiceTransactionGroupComparisonStatisticsPeriods({ numBuckets, latencyAggregationType: latencyAggregationType as LatencyAggregationType, environment, + kuery, }; const currentPeriodPromise = getServiceTransactionGroupComparisonStatistics({ From 356ca07569d7a2328c7a18ab885ac84ba72776f4 Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Wed, 24 Feb 2021 09:23:01 -0500 Subject: [PATCH 07/13] fixing tests --- .../transactions/transactions_groups_comparison_statistics.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts index 90221eeedad97..cf3db799cdfbc 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts @@ -182,7 +182,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { url.format({ pathname: `/api/apm/services/opbeans-java/transactions/groups/comparison_statistics`, query: { - uiFilters: '{}', numBuckets: 20, transactionType: 'request', latencyAggregationType: 'avg', From b89f4a18ee010f8dd172feb936290fa4975c3335 Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Wed, 24 Feb 2021 09:44:09 -0500 Subject: [PATCH 08/13] addressing PR comments --- ...transaction_group_comparison_statistics.ts | 46 ++++++++----------- .../offset_previous_period_coordinate.ts | 27 +++++++++-- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts index 7c6700ab9e773..1cf72b246e7af 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts @@ -20,7 +20,7 @@ import { kqlQuery, } from '../../../server/utils/queries'; import { Coordinate } from '../../../typings/timeseries'; -import { offsetPreviousPeriodCoordinates } from '../../utils/offset_previous_period_coordinate'; +import { offsetXCoordinate } from '../../utils/offset_previous_period_coordinate'; import { withApmSpan } from '../../utils/with_apm_span'; import { getDocumentTypeFilterForAggregatedTransactions, @@ -47,6 +47,7 @@ export async function getServiceTransactionGroupComparisonStatistics({ latencyAggregationType, start, end, + getOffsetXCoordinate, }: { environment?: string; kuery?: string; @@ -59,6 +60,7 @@ export async function getServiceTransactionGroupComparisonStatistics({ latencyAggregationType: LatencyAggregationType; start: number; end: number; + getOffsetXCoordinate?: (x: number) => number; }): Promise< Array<{ transactionName: string; @@ -151,7 +153,9 @@ export async function getServiceTransactionGroupComparisonStatistics({ return buckets.map((bucket) => { const transactionName = bucket.key as string; const latency = bucket.timeseries.buckets.map((timeseriesBucket) => ({ - x: timeseriesBucket.key, + x: getOffsetXCoordinate + ? getOffsetXCoordinate(timeseriesBucket.key) + : timeseriesBucket.key, y: getLatencyValue({ latencyAggregationType, aggregation: timeseriesBucket.latency, @@ -159,12 +163,16 @@ export async function getServiceTransactionGroupComparisonStatistics({ })); const throughput = bucket.timeseries.buckets.map( (timeseriesBucket) => ({ - x: timeseriesBucket.key, + x: getOffsetXCoordinate + ? getOffsetXCoordinate(timeseriesBucket.key) + : timeseriesBucket.key, y: timeseriesBucket.throughput_rate.value, }) ); const errorRate = bucket.timeseries.buckets.map((timeseriesBucket) => ({ - x: timeseriesBucket.key, + x: getOffsetXCoordinate + ? getOffsetXCoordinate(timeseriesBucket.key) + : timeseriesBucket.key, y: calculateTransactionErrorPercentage( timeseriesBucket[EVENT_OUTCOME] ), @@ -236,30 +244,12 @@ export async function getServiceTransactionGroupComparisonStatisticsPeriods({ ...commomProps, start: comparisonStart, end: comparisonEnd, - }).then((previousStatistics) => { - return previousStatistics.map( - ({ transactionName, errorRate, throughput, latency, impact }) => { - return { - transactionName, - impact, - errorRate: offsetPreviousPeriodCoordinates({ - currentPeriodStart: start, - previousPeriodStart: comparisonStart, - previousPeriodTimeseries: errorRate, - }), - throughput: offsetPreviousPeriodCoordinates({ - currentPeriodStart: start, - previousPeriodStart: comparisonStart, - previousPeriodTimeseries: throughput, - }), - latency: offsetPreviousPeriodCoordinates({ - currentPeriodStart: start, - previousPeriodStart: comparisonStart, - previousPeriodTimeseries: latency, - }), - }; - } - ); + getOffsetXCoordinate: (x: number) => + offsetXCoordinate({ + currentPeriodStart: start, + previousPeriodStart: comparisonStart, + x, + }), }) : []; diff --git a/x-pack/plugins/apm/server/utils/offset_previous_period_coordinate.ts b/x-pack/plugins/apm/server/utils/offset_previous_period_coordinate.ts index 837e3d02056f0..c8ae68a761f53 100644 --- a/x-pack/plugins/apm/server/utils/offset_previous_period_coordinate.ts +++ b/x-pack/plugins/apm/server/utils/offset_previous_period_coordinate.ts @@ -8,6 +8,26 @@ import moment from 'moment'; import { Coordinate } from '../../typings/timeseries'; +function getDateDiff({ start, end }: { start: number; end: number }) { + return moment(start).diff(moment(end)); +} + +export function offsetXCoordinate({ + currentPeriodStart, + previousPeriodStart, + x, +}: { + currentPeriodStart: number; + previousPeriodStart: number; + x: number; +}) { + const dateOffset = getDateDiff({ + start: currentPeriodStart, + end: previousPeriodStart, + }); + return moment(x).add(dateOffset).valueOf(); +} + export function offsetPreviousPeriodCoordinates({ currentPeriodStart, previousPeriodStart, @@ -21,9 +41,10 @@ export function offsetPreviousPeriodCoordinates({ return []; } - const dateOffset = moment(currentPeriodStart).diff( - moment(previousPeriodStart) - ); + const dateOffset = getDateDiff({ + start: currentPeriodStart, + end: previousPeriodStart, + }); return previousPeriodTimeseries.map(({ x, y }) => { const offsetX = moment(x).add(dateOffset).valueOf(); From 33308e31e6e8a16d0b2cdf5df99f5b4b39fe8a67 Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Thu, 25 Feb 2021 12:38:00 -0500 Subject: [PATCH 09/13] fixing concurrency issues --- .../index.tsx | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx index 216b5c378a02a..865ee926f50ac 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx @@ -55,6 +55,7 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { }); const { pageIndex, sort } = tableOptions; + const { direction, field } = sort; const { transactionType } = useApmServiceContext(); const { @@ -96,12 +97,13 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { }, }).then((response) => { return { - // Used to refetch the comparison statistics when a new primary statistics were fetched. + // Everytime the primary statistics is refetched, updates the requestId making the comparison API to be refetched. requestId: uuid(), ...response, }; }); }, + // eslint-disable-next-line react-hooks/exhaustive-deps [ environment, kuery, @@ -110,14 +112,18 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { end, transactionType, latencyAggregationType, + comparisonType, + pageIndex, + direction, + field, ] ); const { transactionGroups, requestId } = data; const currentPageTransactionGroups = orderBy( transactionGroups, - sort.field, - sort.direction + field, + direction ).slice(pageIndex * PAGE_SIZE, (pageIndex + 1) * PAGE_SIZE); const transactionNames = JSON.stringify( @@ -158,12 +164,9 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { }); } }, - // only fetches statistics when requestId, transaction names or comparison type change - // requestId: Is used to refetch the comparison data when a new primary statistics were fetched. - // transactionNams: Is used to fetch the comparison data when a user navigate to a different page within the table - // comparison type: Is used to refetch the comparison when the comparison type is changed, either manually by a user or automatically when the date picker is changed + // only fetches comparison statistics when requestId is invalidated by primary statistics api call // eslint-disable-next-line react-hooks/exhaustive-deps - [requestId, transactionNames, comparisonType], + [requestId], { preservePreviousData: false } ); @@ -185,13 +188,6 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { hidePerPageOptions: true, }; - const sorting = { - sort: { - field: sort.field, - direction: sort.direction, - }, - }; - return ( @@ -234,7 +230,7 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { items={currentPageTransactionGroups} columns={columns} pagination={pagination} - sorting={sorting} + sorting={{ sort: { field, direction } }} onChange={(newTableOptions: { page?: { index: number; From f57cd1fd923812bb937724dcf00e37c6027d4f63 Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Sun, 28 Feb 2021 11:02:51 -0500 Subject: [PATCH 10/13] addressing PR comments --- .../service_overview_transactions_table/get_columns.tsx | 8 ++++---- .../public/components/shared/charts/spark_plot/index.tsx | 6 +++--- ...get_service_transaction_group_comparison_statistics.ts | 6 +++--- .../transactions_groups_comparison_statistics.ts | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx index 30dc138e829eb..522dc0cfcd48b 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx @@ -155,19 +155,19 @@ export function getColumns({ ), width: px(unit * 5), render: (_, { name }) => { - const currenIimpact = + const currentImpact = transactionGroupComparisonStatistics?.currentPeriod?.[name]?.impact ?? 0; - const previousIimpact = + const previousImpact = transactionGroupComparisonStatistics?.previousPeriod?.[name] ?.impact ?? 0; return ( - + - + ); diff --git a/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx index e8568ffa278af..3936a81125e1c 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx @@ -75,7 +75,7 @@ export function SparkPlot({ width: compact ? px(unit * 3) : px(unit * 4), }; - const SparklinesSeries = hasComparisonSeries ? LineSeries : AreaSeries; + const SparkelineSeries = hasComparisonSeries ? LineSeries : AreaSeries; return ( @@ -98,8 +98,8 @@ export function SparkPlot({ showLegend={false} tooltip="none" /> - diff --git a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts index cf3db799cdfbc..eb6181c1498e0 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts @@ -199,7 +199,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { previousPeriod = response.body.previousPeriod; }); - it('returns corrent number of items', () => { + it('returns correct number of items', () => { expect(Object.keys(currentPeriod)).to.be.eql(transactionNames); expect(Object.keys(previousPeriod)).to.be.eql(transactionNames); From 467b7ec9a6fd0bc755361a928378c9d4628cdf82 Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Mon, 8 Mar 2021 13:02:05 -0500 Subject: [PATCH 11/13] addressing PR comments --- .../index.tsx | 38 ++++++++++--------- .../shared/charts/spark_plot/index.tsx | 36 +++++++++--------- ...transaction_group_comparison_statistics.ts | 37 +++++++++--------- .../offset_previous_period_coordinate.ts | 27 +------------ ...ansactions_groups_comparison_statistics.ts | 12 +++--- 5 files changed, 67 insertions(+), 83 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx index 865ee926f50ac..02f60eab2cb88 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx @@ -32,6 +32,7 @@ const INITIAL_STATE = { transactionGroups: [], isAggregationAccurate: true, requestId: '', + transactionGroupsTotalItems: 0, }; type SortField = 'name' | 'latency' | 'throughput' | 'errorRate' | 'impact'; @@ -96,13 +97,22 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { }, }, }).then((response) => { + const currentPageTransactionGroups = orderBy( + response.transactionGroups, + field, + direction + ).slice(pageIndex * PAGE_SIZE, (pageIndex + 1) * PAGE_SIZE); + return { + ...response, // Everytime the primary statistics is refetched, updates the requestId making the comparison API to be refetched. requestId: uuid(), - ...response, + transactionGroupsTotalItems: response.transactionGroups.length, + transactionGroups: currentPageTransactionGroups, }; }); }, + // comparisonType is listed as dependency even thought it is not used. This is needed to trigger the comparison api when it is changed. // eslint-disable-next-line react-hooks/exhaustive-deps [ environment, @@ -112,23 +122,14 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { end, transactionType, latencyAggregationType, - comparisonType, pageIndex, direction, field, + comparisonType, ] ); - const { transactionGroups, requestId } = data; - const currentPageTransactionGroups = orderBy( - transactionGroups, - field, - direction - ).slice(pageIndex * PAGE_SIZE, (pageIndex + 1) * PAGE_SIZE); - - const transactionNames = JSON.stringify( - currentPageTransactionGroups.map(({ name }) => name).sort() - ); + const { transactionGroups, requestId, transactionGroupsTotalItems } = data; const { data: transactionGroupComparisonStatistics, @@ -136,8 +137,7 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { } = useFetcher( (callApmApi) => { if ( - status !== FETCH_STATUS.LOADING && - currentPageTransactionGroups.length && + transactionGroupsTotalItems && start && end && transactionType && @@ -156,7 +156,9 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { numBuckets: 20, transactionType, latencyAggregationType, - transactionNames, + transactionNames: JSON.stringify( + transactionGroups.map(({ name }) => name).sort() + ), comparisonStart, comparisonEnd, }, @@ -184,7 +186,7 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { const pagination = { pageIndex, pageSize: PAGE_SIZE, - totalItemCount: transactionGroups.length, + totalItemCount: transactionGroupsTotalItems, hidePerPageOptions: true, }; @@ -223,11 +225,11 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { point.y === null); +function hasValidTimeseries( + series?: Coordinate[] | null +): series is Coordinate[] { + return !!series?.some((point) => point.y !== null); } export function SparkPlot({ @@ -75,31 +77,20 @@ export function SparkPlot({ width: compact ? px(unit * 3) : px(unit * 4), }; - const SparkelineSeries = hasComparisonSeries ? LineSeries : AreaSeries; + const Sparkline = hasComparisonSeries ? LineSeries : AreaSeries; return ( - {!series || isEmptyTimeseries(series) ? ( -
- -
- ) : ( + {hasValidTimeseries(series) ? ( - )} + ) : ( +
+ +
)}
diff --git a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts index c298e5e2240c2..c929136f88a46 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts @@ -20,7 +20,10 @@ import { kqlQuery, } from '../../../server/utils/queries'; import { Coordinate } from '../../../typings/timeseries'; -import { offsetXCoordinate } from '../../utils/offset_previous_period_coordinate'; +import { + offsetPreviousPeriodCoordinates, + offsetXCoordinate, +} from '../../utils/offset_previous_period_coordinate'; import { withApmSpan } from '../../utils/with_apm_span'; import { getDocumentTypeFilterForAggregatedTransactions, @@ -60,7 +63,7 @@ export async function getServiceTransactionGroupComparisonStatistics({ latencyAggregationType: LatencyAggregationType; start: number; end: number; - getOffsetXCoordinate?: (x: number) => number; + getOffsetXCoordinate?: (timeseries: Coordinate[]) => Coordinate[]; }): Promise< Array<{ transactionName: string; @@ -153,9 +156,7 @@ export async function getServiceTransactionGroupComparisonStatistics({ return buckets.map((bucket) => { const transactionName = bucket.key as string; const latency = bucket.timeseries.buckets.map((timeseriesBucket) => ({ - x: getOffsetXCoordinate - ? getOffsetXCoordinate(timeseriesBucket.key) - : timeseriesBucket.key, + x: timeseriesBucket.key, y: getLatencyValue({ latencyAggregationType, aggregation: timeseriesBucket.latency, @@ -163,16 +164,12 @@ export async function getServiceTransactionGroupComparisonStatistics({ })); const throughput = bucket.timeseries.buckets.map( (timeseriesBucket) => ({ - x: getOffsetXCoordinate - ? getOffsetXCoordinate(timeseriesBucket.key) - : timeseriesBucket.key, + x: timeseriesBucket.key, y: timeseriesBucket.throughput_rate.value, }) ); const errorRate = bucket.timeseries.buckets.map((timeseriesBucket) => ({ - x: getOffsetXCoordinate - ? getOffsetXCoordinate(timeseriesBucket.key) - : timeseriesBucket.key, + x: timeseriesBucket.key, y: calculateTransactionErrorPercentage( timeseriesBucket[EVENT_OUTCOME] ), @@ -181,9 +178,15 @@ export async function getServiceTransactionGroupComparisonStatistics({ bucket.transaction_group_total_duration.value || 0; return { transactionName, - latency, - throughput, - errorRate, + latency: getOffsetXCoordinate + ? getOffsetXCoordinate(latency) + : latency, + throughput: getOffsetXCoordinate + ? getOffsetXCoordinate(throughput) + : throughput, + errorRate: getOffsetXCoordinate + ? getOffsetXCoordinate(errorRate) + : errorRate, impact: totalDuration ? (transactionGroupTotalDuration * 100) / totalDuration : 0, @@ -244,11 +247,11 @@ export async function getServiceTransactionGroupComparisonStatisticsPeriods({ ...commonProps, start: comparisonStart, end: comparisonEnd, - getOffsetXCoordinate: (x: number) => - offsetXCoordinate({ + getOffsetXCoordinate: (timeseries: Coordinate[]) => + offsetPreviousPeriodCoordinates({ currentPeriodStart: start, previousPeriodStart: comparisonStart, - x, + previousPeriodTimeseries: timeseries, }), }) : []; diff --git a/x-pack/plugins/apm/server/utils/offset_previous_period_coordinate.ts b/x-pack/plugins/apm/server/utils/offset_previous_period_coordinate.ts index c8ae68a761f53..7ca153ec6181f 100644 --- a/x-pack/plugins/apm/server/utils/offset_previous_period_coordinate.ts +++ b/x-pack/plugins/apm/server/utils/offset_previous_period_coordinate.ts @@ -8,26 +8,6 @@ import moment from 'moment'; import { Coordinate } from '../../typings/timeseries'; -function getDateDiff({ start, end }: { start: number; end: number }) { - return moment(start).diff(moment(end)); -} - -export function offsetXCoordinate({ - currentPeriodStart, - previousPeriodStart, - x, -}: { - currentPeriodStart: number; - previousPeriodStart: number; - x: number; -}) { - const dateOffset = getDateDiff({ - start: currentPeriodStart, - end: previousPeriodStart, - }); - return moment(x).add(dateOffset).valueOf(); -} - export function offsetPreviousPeriodCoordinates({ currentPeriodStart, previousPeriodStart, @@ -41,13 +21,10 @@ export function offsetPreviousPeriodCoordinates({ return []; } - const dateOffset = getDateDiff({ - start: currentPeriodStart, - end: previousPeriodStart, - }); + const dateDiff = currentPeriodStart - previousPeriodStart; return previousPeriodTimeseries.map(({ x, y }) => { - const offsetX = moment(x).add(dateOffset).valueOf(); + const offsetX = moment(x).add(dateDiff).valueOf(); return { x: offsetX, y, diff --git a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts index eb6181c1498e0..1065bc9405838 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_comparison_statistics.ts @@ -75,7 +75,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { previousPeriod, } = response.body as TransactionsGroupsComparisonStatistics; - expect(Object.keys(currentPeriod)).to.be.eql(transactionNames); + expect(Object.keys(currentPeriod).sort()).to.be.eql(transactionNames.sort()); const currentPeriodItems = Object.values(currentPeriod).map((data) => data); const previousPeriodItems = Object.values(previousPeriod).map((data) => data); @@ -129,10 +129,10 @@ export default function ApiTest({ getService }: FtrProviderContext) { previousPeriod, } = response.body as TransactionsGroupsComparisonStatistics; - expect(Object.keys(currentPeriod)).to.be.eql(transactionNames); + expect(Object.keys(currentPeriod).sort()).to.be.eql(transactionNames.sort()); - const currentPeriodItems = Object.values(currentPeriod).map((data) => data); - const previousPeriodItems = Object.values(previousPeriod).map((data) => data); + const currentPeriodItems = Object.values(currentPeriod); + const previousPeriodItems = Object.values(previousPeriod); expect(previousPeriodItems).to.be.empty(); @@ -200,8 +200,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); it('returns correct number of items', () => { - expect(Object.keys(currentPeriod)).to.be.eql(transactionNames); - expect(Object.keys(previousPeriod)).to.be.eql(transactionNames); + expect(Object.keys(currentPeriod).sort()).to.be.eql(transactionNames.sort()); + expect(Object.keys(previousPeriod).sort()).to.be.eql(transactionNames.sort()); transactionNames.forEach((transactionName) => { expect(currentPeriod[transactionName]).not.to.be.empty(); From dc361b13883b6640bbdb45eaa758a1078b43980e Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Mon, 8 Mar 2021 13:31:13 -0500 Subject: [PATCH 12/13] addressing PR comments --- .../get_service_transaction_group_comparison_statistics.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts index c929136f88a46..ebdb5fb5bbdc2 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts @@ -20,10 +20,7 @@ import { kqlQuery, } from '../../../server/utils/queries'; import { Coordinate } from '../../../typings/timeseries'; -import { - offsetPreviousPeriodCoordinates, - offsetXCoordinate, -} from '../../utils/offset_previous_period_coordinate'; +import { offsetPreviousPeriodCoordinates } from '../../utils/offset_previous_period_coordinate'; import { withApmSpan } from '../../utils/with_apm_span'; import { getDocumentTypeFilterForAggregatedTransactions, From 2c298e407483aa32a617569ab02ee18449ace16b Mon Sep 17 00:00:00 2001 From: cauemarcondes Date: Mon, 8 Mar 2021 19:45:15 -0500 Subject: [PATCH 13/13] hiding impact bar when comparison disable --- .../service_overview_transactions_table/get_columns.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx index 522dc0cfcd48b..bff45b5d274c3 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/get_columns.tsx @@ -166,9 +166,11 @@ export function getColumns({ - - - + {comparisonEnabled && ( + + + + )}
); },