diff --git a/x-pack/plugins/apm/server/utils/offset_previous_period_coordinate.test.ts b/x-pack/plugins/apm/common/utils/offset_previous_period_coordinate.test.ts similarity index 100% rename from x-pack/plugins/apm/server/utils/offset_previous_period_coordinate.test.ts rename to x-pack/plugins/apm/common/utils/offset_previous_period_coordinate.test.ts diff --git a/x-pack/plugins/apm/server/utils/offset_previous_period_coordinate.ts b/x-pack/plugins/apm/common/utils/offset_previous_period_coordinate.ts similarity index 100% rename from x-pack/plugins/apm/server/utils/offset_previous_period_coordinate.ts rename to x-pack/plugins/apm/common/utils/offset_previous_period_coordinate.ts diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx index 4ff42b151dc8e..55da021e04687 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx @@ -13,7 +13,10 @@ import { EuiTitle, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { keyBy } from 'lodash'; import React from 'react'; +import { offsetPreviousPeriodCoordinates } from '../../../../../common/utils/offset_previous_period_coordinate'; +import { Coordinate } from '../../../../../typings/timeseries'; import { getNextEnvironmentUrlParam } from '../../../../../common/environment_filter_values'; import { asMillisecondDuration, @@ -32,6 +35,7 @@ import { ServiceMapLink } from '../../../shared/Links/apm/ServiceMapLink'; import { ServiceOverviewLink } from '../../../shared/Links/apm/service_overview_link'; import { SpanIcon } from '../../../shared/span_icon'; import { TableFetchWrapper } from '../../../shared/table_fetch_wrapper'; +import { getTimeRangeComparison } from '../../../shared/time_comparison/get_time_range_comparison'; import { TruncateWithTooltip } from '../../../shared/truncate_with_tooltip'; import { ServiceOverviewTableContainer } from '../service_overview_table_container'; @@ -39,12 +43,68 @@ interface Props { serviceName: string; } +type ServiceDependencyPeriods = ServiceDependencyItem & { + latency: { previousPeriodTimeseries?: Coordinate[] }; + throughput: { previousPeriodTimeseries?: Coordinate[] }; + errorRate: { previousPeriodTimeseries?: Coordinate[] }; + previousPeriodImpact?: number; +}; + +function mergeCurrentAndPreviousPeriods({ + currentPeriod = [], + previousPeriod = [], +}: { + currentPeriod?: ServiceDependencyItem[]; + previousPeriod?: ServiceDependencyItem[]; +}): ServiceDependencyPeriods[] { + const previousPeriodMap = keyBy(previousPeriod, 'name'); + + return currentPeriod.map((currentDependency) => { + const previousDependency = previousPeriodMap[currentDependency.name]; + if (!previousDependency) { + return currentDependency; + } + return { + ...currentDependency, + latency: { + ...currentDependency.latency, + previousPeriodTimeseries: offsetPreviousPeriodCoordinates({ + currentPeriodTimeseries: currentDependency.latency.timeseries, + previousPeriodTimeseries: previousDependency.latency?.timeseries, + }), + }, + throughput: { + ...currentDependency.throughput, + previousPeriodTimeseries: offsetPreviousPeriodCoordinates({ + currentPeriodTimeseries: currentDependency.throughput.timeseries, + previousPeriodTimeseries: previousDependency.throughput?.timeseries, + }), + }, + errorRate: { + ...currentDependency.errorRate, + previousPeriodTimeseries: offsetPreviousPeriodCoordinates({ + currentPeriodTimeseries: currentDependency.errorRate.timeseries, + previousPeriodTimeseries: previousDependency.errorRate?.timeseries, + }), + }, + previousPeriodImpact: previousDependency.impact, + }; + }); +} + export function ServiceOverviewDependenciesTable({ serviceName }: Props) { const { - urlParams: { start, end, environment }, + urlParams: { start, end, environment, comparisonEnabled, comparisonType }, } = useUrlParams(); - const columns: Array> = [ + const { comparisonStart, comparisonEnd } = getTimeRangeComparison({ + start, + end, + comparisonEnabled, + comparisonType, + }); + + const columns: Array> = [ { field: 'name', name: i18n.translate( @@ -102,6 +162,9 @@ export function ServiceOverviewDependenciesTable({ serviceName }: Props) { ); @@ -121,6 +184,11 @@ export function ServiceOverviewDependenciesTable({ serviceName }: Props) { compact color="euiColorVis0" series={throughput.timeseries} + comparisonSeries={ + comparisonEnabled + ? throughput.previousPeriodTimeseries + : undefined + } valueLabel={asTransactionRate(throughput.value)} /> ); @@ -142,6 +210,9 @@ export function ServiceOverviewDependenciesTable({ serviceName }: Props) { compact color="euiColorVis7" series={errorRate.timeseries} + comparisonSeries={ + comparisonEnabled ? errorRate.previousPeriodTimeseries : undefined + } valueLabel={asPercent(errorRate.value, 1)} /> ); @@ -157,13 +228,28 @@ export function ServiceOverviewDependenciesTable({ serviceName }: Props) { } ), width: px(unit * 5), - render: (_, { impact }) => { - return ; + render: (_, { impact, previousPeriodImpact }) => { + return ( + + + + + {comparisonEnabled && previousPeriodImpact !== undefined && ( + + + + )} + + ); }, sortable: true, }, ]; - + // Fetches current period dependencies const { data, status } = useFetcher( (callApmApi) => { if (!start || !end) { @@ -173,22 +259,41 @@ export function ServiceOverviewDependenciesTable({ serviceName }: Props) { return callApmApi({ endpoint: 'GET /api/apm/services/{serviceName}/dependencies', params: { - path: { - serviceName, - }, + path: { serviceName }, + query: { start, end, environment, numBuckets: 20 }, + }, + }); + }, + [start, end, serviceName, environment] + ); + + // Fetches previous period dependencies + const { data: previousPeriodData, status: previousPeriodStatus } = useFetcher( + (callApmApi) => { + if (!comparisonStart || !comparisonEnd) { + return; + } + + return callApmApi({ + endpoint: 'GET /api/apm/services/{serviceName}/dependencies', + params: { + path: { serviceName }, query: { - start, - end, + start: comparisonStart, + end: comparisonEnd, environment, numBuckets: 20, }, }, }); }, - [start, end, serviceName, environment] + [comparisonStart, comparisonEnd, serviceName, environment] ); - const serviceDependencies = data?.serviceDependencies ?? []; + const serviceDependencies = mergeCurrentAndPreviousPeriods({ + currentPeriod: data?.serviceDependencies, + previousPeriod: previousPeriodData?.serviceDependencies, + }); // need top-level sortable fields for the managed table const items = serviceDependencies.map((item) => ({ @@ -238,7 +343,10 @@ export function ServiceOverviewDependenciesTable({ serviceName }: Props) { columns={columns} items={items} allowNeutralSort={false} - loading={status === FETCH_STATUS.LOADING} + loading={ + status === FETCH_STATUS.LOADING || + previousPeriodStatus === FETCH_STATUS.LOADING + } pagination={{ initialPageSize: 5, pageSizeOptions: [5], 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 02aad49ddfc9c..9ac1c7d64d8b2 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 @@ -162,7 +162,7 @@ export function getColumns({ - {comparisonEnabled && previousImpact && ( + {comparisonEnabled && previousImpact !== undefined && ( diff --git a/x-pack/plugins/apm/server/lib/services/get_service_error_groups/get_service_error_group_detailed_statistics.ts b/x-pack/plugins/apm/server/lib/services/get_service_error_groups/get_service_error_group_detailed_statistics.ts index dd41269f0bad6..e45864de2fc1e 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_error_groups/get_service_error_group_detailed_statistics.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_error_groups/get_service_error_group_detailed_statistics.ts @@ -5,6 +5,7 @@ * 2.0. */ import { keyBy } from 'lodash'; +import { offsetPreviousPeriodCoordinates } from '../../../../common/utils/offset_previous_period_coordinate'; import { Coordinate } from '../../../../typings/timeseries'; import { ERROR_GROUP_ID, @@ -17,7 +18,6 @@ import { rangeQuery, kqlQuery, } from '../../../../server/utils/queries'; -import { offsetPreviousPeriodCoordinates } from '../../../utils/offset_previous_period_coordinate'; import { withApmSpan } from '../../../utils/with_apm_span'; import { getBucketSize } from '../../helpers/get_bucket_size'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; diff --git a/x-pack/plugins/apm/server/lib/services/get_service_instances/detailed_statistics.ts b/x-pack/plugins/apm/server/lib/services/get_service_instances/detailed_statistics.ts index 85414100a1563..804ed91c54a51 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_instances/detailed_statistics.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_instances/detailed_statistics.ts @@ -6,10 +6,10 @@ */ import { keyBy } from 'lodash'; +import { offsetPreviousPeriodCoordinates } from '../../../../common/utils/offset_previous_period_coordinate'; import { Coordinate } from '../../../../typings/timeseries'; import { LatencyAggregationType } from '../../../../common/latency_aggregation_types'; import { joinByKey } from '../../../../common/utils/join_by_key'; -import { offsetPreviousPeriodCoordinates } from '../../../utils/offset_previous_period_coordinate'; import { withApmSpan } from '../../../utils/with_apm_span'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { getServiceInstancesSystemMetricStatistics } from './get_service_instances_system_metric_statistics'; diff --git a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_detailed_statistics.ts b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_detailed_statistics.ts index 314d6c7bd1458..f14dba69bf404 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_detailed_statistics.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_detailed_statistics.ts @@ -6,6 +6,7 @@ */ import { keyBy } from 'lodash'; +import { offsetPreviousPeriodCoordinates } from '../../../common/utils/offset_previous_period_coordinate'; import { EVENT_OUTCOME, SERVICE_NAME, @@ -20,7 +21,6 @@ import { kqlQuery, } from '../../../server/utils/queries'; import { Coordinate } from '../../../typings/timeseries'; -import { offsetPreviousPeriodCoordinates } from '../../utils/offset_previous_period_coordinate'; import { withApmSpan } from '../../utils/with_apm_span'; import { getDocumentTypeFilterForAggregatedTransactions, diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts b/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts index ec5dd1308cb7e..71f803a03bf85 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { offsetPreviousPeriodCoordinates } from '../../../common/utils/offset_previous_period_coordinate'; import { Coordinate } from '../../../typings/timeseries'; import { @@ -31,7 +32,6 @@ import { getTransactionErrorRateTimeSeries, } from '../helpers/transaction_error_rate'; import { withApmSpan } from '../../utils/with_apm_span'; -import { offsetPreviousPeriodCoordinates } from '../../utils/offset_previous_period_coordinate'; export async function getErrorRate({ environment, diff --git a/x-pack/plugins/apm/server/lib/transactions/get_latency_charts/index.ts b/x-pack/plugins/apm/server/lib/transactions/get_latency_charts/index.ts index 468585ddd23cb..5a58360597828 100644 --- a/x-pack/plugins/apm/server/lib/transactions/get_latency_charts/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/get_latency_charts/index.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { offsetPreviousPeriodCoordinates } from '../../../../common/utils/offset_previous_period_coordinate'; import { ESFilter } from '../../../../../../../typings/elasticsearch'; import { PromiseReturnType } from '../../../../../observability/typings/common'; import { @@ -25,7 +26,6 @@ import { } from '../../../lib/helpers/aggregated_transactions'; import { getBucketSize } from '../../../lib/helpers/get_bucket_size'; import { Setup, SetupTimeRange } from '../../../lib/helpers/setup_request'; -import { offsetPreviousPeriodCoordinates } from '../../../utils/offset_previous_period_coordinate'; import { withApmSpan } from '../../../utils/with_apm_span'; import { getLatencyAggregation, diff --git a/x-pack/plugins/apm/server/routes/services.ts b/x-pack/plugins/apm/server/routes/services.ts index a27c7d5ba38d2..51d2fe7aeeb95 100644 --- a/x-pack/plugins/apm/server/routes/services.ts +++ b/x-pack/plugins/apm/server/routes/services.ts @@ -30,7 +30,6 @@ import { getServiceTransactionTypes } from '../lib/services/get_service_transact import { getThroughput } from '../lib/services/get_throughput'; import { getServiceProfilingStatistics } from '../lib/services/profiling/get_service_profiling_statistics'; import { getServiceProfilingTimeline } from '../lib/services/profiling/get_service_profiling_timeline'; -import { offsetPreviousPeriodCoordinates } from '../utils/offset_previous_period_coordinate'; import { withApmSpan } from '../utils/with_apm_span'; import { createApmServerRoute } from './create_apm_server_route'; import { createApmServerRouteRepository } from './create_apm_server_route_repository'; @@ -40,6 +39,7 @@ import { kueryRt, rangeRt, } from './default_api_types'; +import { offsetPreviousPeriodCoordinates } from '../../common/utils/offset_previous_period_coordinate'; const servicesRoute = createApmServerRoute({ endpoint: 'GET /api/apm/services',