Skip to content

Commit

Permalink
[APM] Service view for all dependencies (elastic#107627)
Browse files Browse the repository at this point in the history
* [APM] Service view for all dependencies

Closes elastic#103257.

* Update API tests

* Fix type issue
  • Loading branch information
dgieselaar authored and kibanamachine committed Aug 5, 2021
1 parent 7a9398d commit d2ed3a3
Show file tree
Hide file tree
Showing 15 changed files with 284 additions and 28 deletions.
4 changes: 4 additions & 0 deletions x-pack/plugins/apm/common/connections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ export interface ConnectionStatsItem {
value: number | null;
timeseries: Coordinate[];
};
totalTime: {
value: number | null;
timeseries: Coordinate[];
};
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ export function BackendInventoryDependenciesTable() {
return callApmApi({
endpoint: 'GET /api/apm/backends/top_backends',
params: {
query: { start, end, environment, numBuckets: 20, offset },
query: { start, end, environment, numBuckets: 20, offset, kuery },
},
});
},
[start, end, environment, offset]
[start, end, environment, offset, kuery]
);

const dependencies =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,35 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { EuiSpacer } from '@elastic/eui';
import { EuiTitle } from '@elastic/eui';
import { EuiPanel } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { ChartPointerEventContextProvider } from '../../../context/chart_pointer_event/chart_pointer_event_context';
import { ServiceOverviewDependenciesTable } from '../service_overview/service_overview_dependencies_table';
import { ServiceDependenciesBreakdownChart } from './service_dependencies_breakdown_chart';

export function ServiceDependencies() {
return <></>;
return (
<>
<ChartPointerEventContextProvider>
<EuiPanel hasBorder={true}>
<EuiTitle size="xs">
<h2>
{i18n.translate(
'xpack.apm.serviceDependencies.breakdownChartTitle',
{
defaultMessage: 'Time spent by dependency',
}
)}
</h2>
</EuiTitle>
<ServiceDependenciesBreakdownChart height={200} />
</EuiPanel>
</ChartPointerEventContextProvider>
<EuiSpacer size="m" />
<ServiceOverviewDependenciesTable />
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* 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 React from 'react';
import { getVizColorForIndex } from '../../../../common/viz_colors';
import { Coordinate, TimeSeries } from '../../../../typings/timeseries';
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
import { useApmParams } from '../../../hooks/use_apm_params';
import { useFetcher } from '../../../hooks/use_fetcher';
import { useTimeRange } from '../../../hooks/use_time_range';
import { BreakdownChart } from '../../shared/charts/breakdown_chart';

export function ServiceDependenciesBreakdownChart({
height,
}: {
height: number;
}) {
const { start, end } = useTimeRange();
const { serviceName } = useApmServiceContext();

const {
query: { kuery, environment },
} = useApmParams('/services/:serviceName/dependencies');

const { data, status } = useFetcher(
(callApmApi) => {
return callApmApi({
endpoint: 'GET /api/apm/services/{serviceName}/dependencies/breakdown',
params: {
path: {
serviceName,
},
query: {
start,
end,
kuery,
environment,
},
},
});
},
[serviceName, start, end, kuery, environment]
);

const timeseries: Array<TimeSeries<Coordinate>> =
data?.breakdown.map((item, index) => {
return {
title: item.title,
data: item.data,
type: 'area',
color: getVizColorForIndex(index),
};
}) ?? [];

return (
<BreakdownChart
fetchStatus={status}
height={height}
showAnnotations={false}
annotations={[]}
timeseries={timeseries}
yAxisType="duration"
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function ServiceOverviewDependenciesTable() {
const {
query,
query: { kuery, rangeFrom, rangeTo },
} = useApmParams('/services/:serviceName/overview');
} = useApmParams('/services/:serviceName/*');

const { offset } = getTimeRangeComparison({
start,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,21 @@ import {
Position,
ScaleType,
Settings,
TickFormatter,
} from '@elastic/charts';
import { EuiIcon } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import moment from 'moment';
import React from 'react';
import { useHistory } from 'react-router-dom';
import { Annotation } from '../../../../../common/annotations';
import { useChartTheme } from '../../../../../../observability/public';
import {
asAbsoluteDateTime,
asDuration,
asPercent,
} from '../../../../../common/utils/formatters';
import { Coordinate, TimeSeries } from '../../../../../typings/timeseries';
import { useAnnotationsContext } from '../../../../context/annotations/use_annotations_context';
import { useChartPointerEventContext } from '../../../../context/chart_pointer_event/use_chart_pointer_event_context';
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
import { FETCH_STATUS } from '../../../../hooks/use_fetcher';
Expand All @@ -41,17 +43,23 @@ interface Props {
fetchStatus: FETCH_STATUS;
height?: number;
showAnnotations: boolean;
annotations: Annotation[];
timeseries?: Array<TimeSeries<Coordinate>>;
yAxisType: 'duration' | 'percentage';
}

export function TransactionBreakdownChartContents({
const asPercentBound = (y: number | null) => asPercent(y, 1);
const asDurationBound = (y: number | null) => asDuration(y);

export function BreakdownChart({
fetchStatus,
height = unit * 16,
showAnnotations,
annotations,
timeseries,
yAxisType,
}: Props) {
const history = useHistory();
const { annotations } = useAnnotationsContext();
const chartTheme = useChartTheme();

const { chartRef, setPointerEvent } = useChartPointerEventContext();
Expand All @@ -68,6 +76,9 @@ export function TransactionBreakdownChartContents({

const isEmpty = isTimeseriesEmpty(timeseries);

const yTickFormat: TickFormatter =
yAxisType === 'duration' ? asDurationBound : asPercentBound;

return (
<ChartContainer height={height} hasData={!isEmpty} status={fetchStatus}>
<Chart ref={chartRef}>
Expand Down Expand Up @@ -98,7 +109,7 @@ export function TransactionBreakdownChartContents({
id="y-axis"
ticks={3}
position={Position.Left}
tickFormat={(y: number) => asPercent(y ?? 0, 1)}
tickFormat={yTickFormat}
/>

{showAnnotations && (
Expand Down Expand Up @@ -133,7 +144,9 @@ export function TransactionBreakdownChartContents({
yAccessors={['y']}
data={serie.data}
stackAccessors={['x']}
stackMode={'percentage'}
stackMode={
yAxisType === 'percentage' ? 'percentage' : undefined
}
color={serie.areaColor}
curve={CurveType.CURVE_MONOTONE_X}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiTitle } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { useAnnotationsContext } from '../../../../context/annotations/use_annotations_context';
import { useTransactionBreakdown } from './use_transaction_breakdown';
import { TransactionBreakdownChartContents } from './transaction_breakdown_chart_contents';
import { BreakdownChart } from '../breakdown_chart';

export function TransactionBreakdownChart({
height,
Expand All @@ -19,6 +20,7 @@ export function TransactionBreakdownChart({
showAnnotations?: boolean;
}) {
const { data, status } = useTransactionBreakdown();
const { annotations } = useAnnotationsContext();
const { timeseries } = data;

return (
Expand All @@ -34,11 +36,13 @@ export function TransactionBreakdownChart({
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<TransactionBreakdownChartContents
<BreakdownChart
fetchStatus={status}
height={height}
annotations={annotations}
showAnnotations={showAnnotations}
timeseries={timeseries}
yAxisType="percentage"
/>
</EuiFlexItem>
</EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
* 2.0.
*/

import { SPAN_DESTINATION_SERVICE_RESOURCE } from '../../../common/elasticsearch_fieldnames';
import {
SPAN_DESTINATION_SERVICE_RESOURCE,
SPAN_DESTINATION_SERVICE_RESPONSE_TIME_COUNT,
} from '../../../common/elasticsearch_fieldnames';
import { environmentQuery } from '../../../common/utils/environment_query';
import { kqlQuery, rangeQuery } from '../../../../observability/server';
import { ProcessorEvent } from '../../../common/processor_event';
Expand Down Expand Up @@ -63,7 +66,10 @@ export async function getThroughputChartsForBackend({
}),
aggs: {
throughput: {
rate: {},
rate: {
field: SPAN_DESTINATION_SERVICE_RESPONSE_TIME_COUNT,
unit: 'minute',
},
},
},
},
Expand Down
7 changes: 5 additions & 2 deletions x-pack/plugins/apm/server/lib/backends/get_top_backends.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
* 2.0.
*/

import { kqlQuery } from '../../../../observability/server';
import { NodeType } from '../../../common/connections';
import { environmentQuery } from '../../../common/utils/environment_query';
import { getConnectionStats } from '../connections/get_connection_stats';
import { getConnectionStatsItemsWithRelativeImpact } from '../connections/get_connection_stats/get_connection_stats_items_with_relative_impact';
import { NodeType } from '../../../common/connections';
import { Setup } from '../helpers/setup_request';

export async function getTopBackends({
Expand All @@ -18,20 +19,22 @@ export async function getTopBackends({
numBuckets,
environment,
offset,
kuery,
}: {
setup: Setup;
start: number;
end: number;
numBuckets: number;
environment?: string;
offset?: string;
kuery?: string;
}) {
const statsItems = await getConnectionStats({
setup,
start,
end,
numBuckets,
filter: [...environmentQuery(environment)],
filter: [...environmentQuery(environment), ...kqlQuery(kuery)],
offset,
collapseBy: 'downstream',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,24 @@ export const getStats = async ({
},
},
},
total_latency_sum: {
sum: {
field: SPAN_DESTINATION_SERVICE_RESPONSE_TIME_SUM,
},
},
total_latency_count: {
sum: {
field: SPAN_DESTINATION_SERVICE_RESPONSE_TIME_COUNT,
},
},
timeseries: {
date_histogram: {
field: '@timestamp',
fixed_interval: getBucketSize({
start: startWithOffset,
end: endWithOffset,
numBuckets,
minBucketSize: 60,
}).intervalString,
extended_bounds: {
min: startWithOffset,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ export function getConnectionStats({
y: point.count > 0 ? point.latency_sum / point.count : null,
})),
},
totalTime: {
value: mergedStats.value.latency_sum,
timeseries: mergedStats.timeseries.map((point) => ({
x: point.x,
y: point.latency_sum,
})),
},
throughput: {
value:
mergedStats.value.count > 0
Expand Down
Loading

0 comments on commit d2ed3a3

Please sign in to comment.