Skip to content

Commit

Permalink
[APM] Add throughput, error rate charts to backend detail page (#107379
Browse files Browse the repository at this point in the history
…) (#107618)
  • Loading branch information
dgieselaar authored Aug 4, 2021
1 parent a57b716 commit 4e42e5d
Show file tree
Hide file tree
Showing 11 changed files with 586 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ export function BackendDetailDependenciesTable() {
path: {
backendName,
},
query: { start, end, environment, numBuckets: 20, offset },
query: { start, end, environment, numBuckets: 20, offset, kuery },
},
});
},
[start, end, environment, offset, backendName]
[start, end, environment, offset, backendName, kuery]
);

const dependencies =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* 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, { useMemo } from 'react';
import { i18n } from '@kbn/i18n';
import { asPercent } from '../../../../common/utils/formatters';
import { useApmBackendContext } from '../../../context/apm_backend/use_apm_backend_context';
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
import { useComparison } from '../../../hooks/use_comparison';
import { useFetcher } from '../../../hooks/use_fetcher';
import { useTimeRange } from '../../../hooks/use_time_range';
import { Coordinate, TimeSeries } from '../../../../typings/timeseries';
import { TimeseriesChart } from '../../shared/charts/timeseries_chart';
import { useTheme } from '../../../hooks/use_theme';

function yLabelFormat(y?: number | null) {
return asPercent(y || 0, 1);
}

export function BackendErrorRateChart({ height }: { height: number }) {
const { backendName } = useApmBackendContext();

const theme = useTheme();

const { start, end } = useTimeRange();

const {
urlParams: { kuery, environment },
} = useUrlParams();

const { offset, comparisonChartTheme } = useComparison();

const { data, status } = useFetcher(
(callApmApi) => {
if (!start || !end) {
return;
}

return callApmApi({
endpoint: 'GET /api/apm/backends/{backendName}/charts/error_rate',
params: {
path: {
backendName,
},
query: {
start,
end,
offset,
kuery,
environment,
},
},
});
},
[backendName, start, end, offset, kuery, environment]
);

const timeseries = useMemo(() => {
const specs: Array<TimeSeries<Coordinate>> = [];

if (data?.currentTimeseries) {
specs.push({
data: data.currentTimeseries,
type: 'linemark',
color: theme.eui.euiColorVis7,
title: i18n.translate('xpack.apm.backendErrorRateChart.chartTitle', {
defaultMessage: 'Error rate',
}),
});
}

if (data?.comparisonTimeseries) {
specs.push({
data: data.comparisonTimeseries,
type: 'area',
color: theme.eui.euiColorMediumShade,
title: i18n.translate(
'xpack.apm.backendErrorRateChart.previousPeriodLabel',
{ defaultMessage: 'Previous period' }
),
});
}

return specs;
}, [data, theme.eui.euiColorVis7, theme.eui.euiColorMediumShade]);

return (
<TimeseriesChart
height={height}
fetchStatus={status}
id="errorRateChart"
customTheme={comparisonChartTheme}
timeseries={timeseries}
yLabelFormat={yLabelFormat}
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export function BackendLatencyChart({ height }: { height: number }) {
specs.push({
data: data.currentTimeseries,
type: 'linemark',
color: theme.eui.euiColorVis0,
color: theme.eui.euiColorVis1,
title: i18n.translate('xpack.apm.backendLatencyChart.chartTitle', {
defaultMessage: 'Latency',
}),
Expand All @@ -85,7 +85,7 @@ export function BackendLatencyChart({ height }: { height: number }) {
}

return specs;
}, [data, theme.eui.euiColorVis0, theme.eui.euiColorMediumShade]);
}, [data, theme.eui.euiColorVis1, theme.eui.euiColorMediumShade]);

const maxY = getMaxY(timeseries);
const latencyFormatter = getDurationFormatter(maxY);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* 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, { useMemo } from 'react';
import { i18n } from '@kbn/i18n';
import { asTransactionRate } from '../../../../common/utils/formatters';
import { useApmBackendContext } from '../../../context/apm_backend/use_apm_backend_context';
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
import { useComparison } from '../../../hooks/use_comparison';
import { useFetcher } from '../../../hooks/use_fetcher';
import { useTimeRange } from '../../../hooks/use_time_range';
import { Coordinate, TimeSeries } from '../../../../typings/timeseries';
import { TimeseriesChart } from '../../shared/charts/timeseries_chart';
import { useTheme } from '../../../hooks/use_theme';

export function BackendThroughputChart({ height }: { height: number }) {
const { backendName } = useApmBackendContext();

const theme = useTheme();

const { start, end } = useTimeRange();

const {
urlParams: { kuery, environment },
} = useUrlParams();

const { offset, comparisonChartTheme } = useComparison();

const { data, status } = useFetcher(
(callApmApi) => {
if (!start || !end) {
return;
}

return callApmApi({
endpoint: 'GET /api/apm/backends/{backendName}/charts/throughput',
params: {
path: {
backendName,
},
query: {
start,
end,
offset,
kuery,
environment,
},
},
});
},
[backendName, start, end, offset, kuery, environment]
);

const timeseries = useMemo(() => {
const specs: Array<TimeSeries<Coordinate>> = [];

if (data?.currentTimeseries) {
specs.push({
data: data.currentTimeseries,
type: 'linemark',
color: theme.eui.euiColorVis0,
title: i18n.translate('xpack.apm.backendThroughputChart.chartTitle', {
defaultMessage: 'Throughput',
}),
});
}

if (data?.comparisonTimeseries) {
specs.push({
data: data.comparisonTimeseries,
type: 'area',
color: theme.eui.euiColorMediumShade,
title: i18n.translate(
'xpack.apm.backendThroughputChart.previousPeriodLabel',
{ defaultMessage: 'Previous period' }
),
});
}

return specs;
}, [data, theme.eui.euiColorVis0, theme.eui.euiColorMediumShade]);

return (
<TimeseriesChart
height={height}
fetchStatus={status}
id="throughputChart"
customTheme={comparisonChartTheme}
timeseries={timeseries}
yLabelFormat={asTransactionRate}
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,20 @@ import { EuiPanel } from '@elastic/eui';
import { EuiFlexGroup } from '@elastic/eui';
import React from 'react';
import { EuiSpacer } from '@elastic/eui';
import { EuiTitle } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { ApmBackendContextProvider } from '../../../context/apm_backend/apm_backend_context';
import { useBreadcrumb } from '../../../context/breadcrumbs/use_breadcrumb';
import { ChartPointerEventContextProvider } from '../../../context/chart_pointer_event/chart_pointer_event_context';
import { useApmParams } from '../../../hooks/use_apm_params';
import { useApmRouter } from '../../../hooks/use_apm_router';
import { ApmMainTemplate } from '../../routing/templates/apm_main_template';
import { SearchBar } from '../../shared/search_bar';
import { BackendLatencyChart } from './backend_latency_chart';
import { BackendInventoryTitle } from '../../routing/home';
import { BackendDetailDependenciesTable } from './backend_detail_dependencies_table';
import { BackendThroughputChart } from './backend_throughput_chart';
import { BackendErrorRateChart } from './backend_error_rate_chart';
import { BackendDetailTemplate } from '../../routing/templates/backend_detail_template';

export function BackendDetailOverview() {
const {
Expand All @@ -43,21 +47,55 @@ export function BackendDetailOverview() {
]);

return (
<ApmMainTemplate pageTitle={backendName}>
<ApmBackendContextProvider>
<ApmBackendContextProvider>
<BackendDetailTemplate title={backendName}>
<SearchBar showTimeComparison />
<ChartPointerEventContextProvider>
<EuiFlexGroup direction="column" gutterSize="s">
<EuiFlexGroup direction="row" gutterSize="s">
<EuiFlexItem>
<EuiPanel hasBorder={true}>
<EuiTitle size="xs">
<h2>
{i18n.translate(
'xpack.apm.backendDetailLatencyChartTitle',
{ defaultMessage: 'Latency' }
)}
</h2>
</EuiTitle>
<BackendLatencyChart height={200} />
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem>
<EuiPanel hasBorder={true}>
<EuiTitle size="xs">
<h2>
{i18n.translate(
'xpack.apm.backendDetailThroughputChartTitle',
{ defaultMessage: 'Throughput' }
)}
</h2>
</EuiTitle>
<BackendThroughputChart height={200} />
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem>
<EuiPanel hasBorder={true}>
<EuiTitle size="xs">
<h2>
{i18n.translate(
'xpack.apm.backendDetailErrorRateChartTitle',
{ defaultMessage: 'Error rate' }
)}
</h2>
</EuiTitle>
<BackendErrorRateChart height={200} />
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
</ChartPointerEventContextProvider>
<EuiSpacer size="m" />
<BackendDetailDependenciesTable />
</ApmBackendContextProvider>
</ApmMainTemplate>
</BackendDetailTemplate>
</ApmBackendContextProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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 { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui';
import React from 'react';
import { useApmBackendContext } from '../../../context/apm_backend/use_apm_backend_context';
import { ApmMainTemplate } from './apm_main_template';
import { SpanIcon } from '../../shared/span_icon';

interface Props {
title: string;
children: React.ReactNode;
}

export function BackendDetailTemplate({ title, children }: Props) {
const {
backendName,
metadata: { data },
} = useApmBackendContext();

const metadata = data?.metadata;

return (
<ApmMainTemplate
pageHeader={{
pageTitle: (
<EuiFlexGroup alignItems="center">
<EuiFlexItem grow={false}>
<EuiTitle size="l">
<h1>{backendName}</h1>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<SpanIcon
type={metadata?.spanType}
subtype={metadata?.spanSubtype}
/>
</EuiFlexItem>
</EuiFlexGroup>
),
}}
>
{children}
</ApmMainTemplate>
);
}
Loading

0 comments on commit 4e42e5d

Please sign in to comment.