From 79448550a4cf219aa6e02fc15b3c563fb3819284 Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Thu, 18 Feb 2021 00:15:03 -0600 Subject: [PATCH] Latency percentile labels and instances table support (#91758) * Add "(avg.)" to dependencies table column label. (This one is always average.) * Add latency aggregation type support to the instances table. * Make the memory usage column a bit wider (it was cut off.) --- .../get_latency_column_label.ts | 38 +++++++++++++++++++ .../index.tsx | 2 +- ...ice_overview_instances_chart_and_table.tsx | 15 ++++++-- .../index.tsx | 14 +++---- .../get_columns.tsx | 28 ++------------ .../get_service_instance_transaction_stats.ts | 23 +++++++---- .../services/get_service_instances/index.ts | 2 + x-pack/plugins/apm/server/routes/services.ts | 13 ++++++- .../translations/translations/ja-JP.json | 4 -- .../translations/translations/zh-CN.json | 4 -- .../tests/service_overview/instances.ts | 3 ++ 11 files changed, 94 insertions(+), 52 deletions(-) create mode 100644 x-pack/plugins/apm/public/components/app/service_overview/get_latency_column_label.ts diff --git a/x-pack/plugins/apm/public/components/app/service_overview/get_latency_column_label.ts b/x-pack/plugins/apm/public/components/app/service_overview/get_latency_column_label.ts new file mode 100644 index 00000000000000..fda45db98d0cae --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/service_overview/get_latency_column_label.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { LatencyAggregationType } from '../../../../common/latency_aggregation_types'; + +export function getLatencyColumnLabel( + latencyAggregationType?: LatencyAggregationType +) { + switch (latencyAggregationType) { + case LatencyAggregationType.avg: + return i18n.translate('xpack.apm.serviceOverview.latencyColumnAvgLabel', { + defaultMessage: 'Latency (avg.)', + }); + + case LatencyAggregationType.p95: + return i18n.translate('xpack.apm.serviceOverview.latencyColumnP95Label', { + defaultMessage: 'Latency (95th)', + }); + + case LatencyAggregationType.p99: + return i18n.translate('xpack.apm.serviceOverview.latencyColumnP99Label', { + defaultMessage: 'Latency (99th)', + }); + + default: + return i18n.translate( + 'xpack.apm.serviceOverview.latencyColumnDefaultLabel', + { + defaultMessage: 'Latency', + } + ); + } +} 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 2f37e8e4238d8b..a4647bc148b1e2 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 @@ -93,7 +93,7 @@ export function ServiceOverviewDependenciesTable({ serviceName }: Props) { name: i18n.translate( 'xpack.apm.serviceOverview.dependenciesTableColumnLatency', { - defaultMessage: 'Latency', + defaultMessage: 'Latency (avg.)', } ), width: px(unit * 10), diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_chart_and_table.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_chart_and_table.tsx index 819d65a5d9415e..2f2aaf3156b93a 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_chart_and_table.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_chart_and_table.tsx @@ -25,13 +25,13 @@ export function ServiceOverviewInstancesChartAndTable({ const { transactionType } = useApmServiceContext(); const { - urlParams: { environment, start, end }, + urlParams: { environment, latencyAggregationType, start, end }, uiFilters, } = useUrlParams(); const { data = [], status } = useFetcher( (callApmApi) => { - if (!start || !end || !transactionType) { + if (!start || !end || !transactionType || !latencyAggregationType) { return; } @@ -44,6 +44,7 @@ export function ServiceOverviewInstancesChartAndTable({ }, query: { environment, + latencyAggregationType, start, end, transactionType, @@ -53,7 +54,15 @@ export function ServiceOverviewInstancesChartAndTable({ }, }); }, - [environment, start, end, serviceName, transactionType, uiFilters] + [ + environment, + latencyAggregationType, + start, + end, + serviceName, + transactionType, + uiFilters, + ] ); return ( diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx index 62ae4b7bc34462..83ad506e8659b6 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx @@ -24,6 +24,7 @@ import { asTransactionRate, } from '../../../../../common/utils/formatters'; import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context'; +import { useUrlParams } from '../../../../context/url_params_context/use_url_params'; import { FETCH_STATUS } from '../../../../hooks/use_fetcher'; import { APIReturnType } from '../../../../services/rest/createCallApmApi'; import { px, unit } from '../../../../style/variables'; @@ -32,6 +33,7 @@ import { MetricOverviewLink } from '../../../shared/Links/apm/MetricOverviewLink import { ServiceNodeMetricOverviewLink } from '../../../shared/Links/apm/ServiceNodeMetricOverviewLink'; import { TableFetchWrapper } from '../../../shared/table_fetch_wrapper'; import { TruncateWithTooltip } from '../../../shared/truncate_with_tooltip'; +import { getLatencyColumnLabel } from '../get_latency_column_label'; import { ServiceOverviewTableContainer } from '../service_overview_table_container'; type ServiceInstanceItem = ValuesType< @@ -50,6 +52,9 @@ export function ServiceOverviewInstancesTable({ status, }: Props) { const { agentName } = useApmServiceContext(); + const { + urlParams: { latencyAggregationType }, + } = useUrlParams(); const columns: Array> = [ { @@ -95,12 +100,7 @@ export function ServiceOverviewInstancesTable({ }, { field: 'latencyValue', - name: i18n.translate( - 'xpack.apm.serviceOverview.instancesTableColumnLatency', - { - defaultMessage: 'Latency', - } - ), + name: getLatencyColumnLabel(latencyAggregationType), width: px(unit * 10), render: (_, { latency }) => { return ( @@ -182,7 +182,7 @@ export function ServiceOverviewInstancesTable({ defaultMessage: 'Memory usage (avg.)', } ), - width: px(unit * 8), + width: px(unit * 9), render: (_, { memoryUsage }) => { return ( ; @@ -28,35 +30,13 @@ type ServiceTransactionGroupItem = ValuesType< >; type TransactionGroupComparisonStatistics = APIReturnType<'GET /api/apm/services/{serviceName}/transactions/groups/comparison_statistics'>; -function getLatencyAggregationTypeLabel(latencyAggregationType?: string) { - switch (latencyAggregationType) { - case 'avg': - return i18n.translate( - 'xpack.apm.serviceOverview.transactionsTableColumnLatency.avg', - { defaultMessage: 'Latency (avg.)' } - ); - - case 'p95': - return i18n.translate( - 'xpack.apm.serviceOverview.transactionsTableColumnLatency.p95', - { defaultMessage: 'Latency (95th)' } - ); - - case 'p99': - return i18n.translate( - 'xpack.apm.serviceOverview.transactionsTableColumnLatency.p99', - { defaultMessage: 'Latency (99th)' } - ); - } -} - export function getColumns({ serviceName, latencyAggregationType, transactionGroupComparisonStatistics, }: { serviceName: string; - latencyAggregationType?: string; + latencyAggregationType?: LatencyAggregationType; transactionGroupComparisonStatistics?: TransactionGroupComparisonStatistics; }): Array> { return [ @@ -88,7 +68,7 @@ export function getColumns({ { field: 'latency', sortable: true, - name: getLatencyAggregationTypeLabel(latencyAggregationType), + name: getLatencyColumnLabel(latencyAggregationType), width: px(unit * 10), render: (_, { latency, name }) => { const timeseries = diff --git a/x-pack/plugins/apm/server/lib/services/get_service_instances/get_service_instance_transaction_stats.ts b/x-pack/plugins/apm/server/lib/services/get_service_instances/get_service_instance_transaction_stats.ts index b56625bcebc998..620fd9828bd37f 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_instances/get_service_instance_transaction_stats.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_instances/get_service_instance_transaction_stats.ts @@ -22,9 +22,14 @@ import { } from '../../helpers/aggregated_transactions'; import { calculateThroughput } from '../../helpers/calculate_throughput'; import { withApmSpan } from '../../../utils/with_apm_span'; +import { + getLatencyAggregation, + getLatencyValue, +} from '../../helpers/latency_aggregation_type'; export async function getServiceInstanceTransactionStats({ environment, + latencyAggregationType, setup, transactionType, serviceName, @@ -46,11 +51,7 @@ export async function getServiceInstanceTransactionStats({ ); const subAggs = { - avg_transaction_duration: { - avg: { - field, - }, - }, + ...getLatencyAggregation(latencyAggregationType, field), failures: { filter: { term: { @@ -117,7 +118,7 @@ export async function getServiceInstanceTransactionStats({ (serviceNodeBucket) => { const { doc_count: count, - avg_transaction_duration: avgTransactionDuration, + latency, key, failures, timeseries, @@ -140,10 +141,16 @@ export async function getServiceInstanceTransactionStats({ })), }, latency: { - value: avgTransactionDuration.value, + value: getLatencyValue({ + aggregation: latency, + latencyAggregationType, + }), timeseries: timeseries.buckets.map((dateBucket) => ({ x: dateBucket.key, - y: dateBucket.avg_transaction_duration.value, + y: getLatencyValue({ + aggregation: dateBucket.latency, + latencyAggregationType, + }), })), }, }; diff --git a/x-pack/plugins/apm/server/lib/services/get_service_instances/index.ts b/x-pack/plugins/apm/server/lib/services/get_service_instances/index.ts index 4c16940e6d2538..7c0124f4ce0040 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_instances/index.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_instances/index.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { LatencyAggregationType } from '../../../../common/latency_aggregation_types'; import { joinByKey } from '../../../../common/utils/join_by_key'; import { withApmSpan } from '../../../utils/with_apm_span'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; @@ -13,6 +14,7 @@ import { getServiceInstanceTransactionStats } from './get_service_instance_trans export interface ServiceInstanceParams { environment?: string; + latencyAggregationType: LatencyAggregationType; setup: Setup & SetupTimeRange; serviceName: string; transactionType: string; diff --git a/x-pack/plugins/apm/server/routes/services.ts b/x-pack/plugins/apm/server/routes/services.ts index e59b438305b349..24c7c6e3e23d7e 100644 --- a/x-pack/plugins/apm/server/routes/services.ts +++ b/x-pack/plugins/apm/server/routes/services.ts @@ -32,6 +32,10 @@ import { uiFiltersRt, } from './default_api_types'; import { withApmSpan } from '../utils/with_apm_span'; +import { + latencyAggregationTypeRt, + LatencyAggregationType, +} from '../../common/latency_aggregation_types'; export const servicesRoute = createRoute({ endpoint: 'GET /api/apm/services', @@ -401,7 +405,11 @@ export const serviceInstancesRoute = createRoute({ serviceName: t.string, }), query: t.intersection([ - t.type({ transactionType: t.string, numBuckets: toNumberRt }), + t.type({ + latencyAggregationType: latencyAggregationTypeRt, + transactionType: t.string, + numBuckets: toNumberRt, + }), environmentRt, uiFiltersRt, rangeRt, @@ -412,6 +420,8 @@ export const serviceInstancesRoute = createRoute({ const setup = await setupRequest(context, request); const { serviceName } = context.params.path; const { environment, transactionType, numBuckets } = context.params.query; + const latencyAggregationType = (context.params.query + .latencyAggregationType as unknown) as LatencyAggregationType; const searchAggregatedTransactions = await getSearchAggregatedTransactions( setup @@ -419,6 +429,7 @@ export const serviceInstancesRoute = createRoute({ return getServiceInstances({ environment, + latencyAggregationType, serviceName, setup, transactionType, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index a6aacd7cf5f095..06de7e37cd2ec9 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -5251,7 +5251,6 @@ "xpack.apm.serviceOverview.errorsTableTitle": "エラー", "xpack.apm.serviceOverview.instancesTableColumnCpuUsage": "CPU使用状況(平均)", "xpack.apm.serviceOverview.instancesTableColumnErrorRate": "エラー率", - "xpack.apm.serviceOverview.instancesTableColumnLatency": "レイテンシ", "xpack.apm.serviceOverview.instancesTableColumnMemoryUsage": "メモリー使用状況(平均)", "xpack.apm.serviceOverview.instancesTableColumnNodeName": "ノード名", "xpack.apm.serviceOverview.instancesTableColumnThroughput": "トラフィック", @@ -5264,9 +5263,6 @@ "xpack.apm.serviceOverview.throughtputChartTitle": "トラフィック", "xpack.apm.serviceOverview.transactionsTableColumnErrorRate": "エラー率", "xpack.apm.serviceOverview.transactionsTableColumnImpact": "インパクト", - "xpack.apm.serviceOverview.transactionsTableColumnLatency.avg": "レイテンシ(平均)", - "xpack.apm.serviceOverview.transactionsTableColumnLatency.p95": "レイテンシ(95 番目)", - "xpack.apm.serviceOverview.transactionsTableColumnLatency.p99": "レイテンシ(99 番目)", "xpack.apm.serviceOverview.transactionsTableColumnName": "名前", "xpack.apm.serviceOverview.transactionsTableLinkText": "トランザクションを表示", "xpack.apm.serviceOverview.transactionsTableTitle": "トランザクション", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index a74a540a701076..419a138f69fe3e 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -5260,7 +5260,6 @@ "xpack.apm.serviceOverview.errorsTableTitle": "错误", "xpack.apm.serviceOverview.instancesTableColumnCpuUsage": "CPU 使用率(平均值)", "xpack.apm.serviceOverview.instancesTableColumnErrorRate": "错误率", - "xpack.apm.serviceOverview.instancesTableColumnLatency": "延迟", "xpack.apm.serviceOverview.instancesTableColumnMemoryUsage": "内存使用率(平均值)", "xpack.apm.serviceOverview.instancesTableColumnNodeName": "节点名称", "xpack.apm.serviceOverview.instancesTableColumnThroughput": "流量", @@ -5273,9 +5272,6 @@ "xpack.apm.serviceOverview.throughtputChartTitle": "流量", "xpack.apm.serviceOverview.transactionsTableColumnErrorRate": "错误率", "xpack.apm.serviceOverview.transactionsTableColumnImpact": "影响", - "xpack.apm.serviceOverview.transactionsTableColumnLatency.avg": "延迟(平均值)", - "xpack.apm.serviceOverview.transactionsTableColumnLatency.p95": "延迟(第 95 个)", - "xpack.apm.serviceOverview.transactionsTableColumnLatency.p99": "延迟(第 99 个)", "xpack.apm.serviceOverview.transactionsTableColumnName": "名称", "xpack.apm.serviceOverview.transactionsTableLinkText": "查看事务", "xpack.apm.serviceOverview.transactionsTableTitle": "事务", diff --git a/x-pack/test/apm_api_integration/tests/service_overview/instances.ts b/x-pack/test/apm_api_integration/tests/service_overview/instances.ts index 7c1b01d2715b66..cca40a6950007f 100644 --- a/x-pack/test/apm_api_integration/tests/service_overview/instances.ts +++ b/x-pack/test/apm_api_integration/tests/service_overview/instances.ts @@ -35,6 +35,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { url.format({ pathname: `/api/apm/services/opbeans-java/service_overview_instances`, query: { + latencyAggregationType: 'avg', start, end, numBuckets: 20, @@ -63,6 +64,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { url.format({ pathname: `/api/apm/services/opbeans-java/service_overview_instances`, query: { + latencyAggregationType: 'avg', start, end, numBuckets: 20, @@ -146,6 +148,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { url.format({ pathname: `/api/apm/services/opbeans-ruby/service_overview_instances`, query: { + latencyAggregationType: 'avg', start, end, numBuckets: 20,