Skip to content

Commit

Permalink
[APM] Correlations GA (elastic#86477)
Browse files Browse the repository at this point in the history
  • Loading branch information
ogupte committed Feb 5, 2021
1 parent fc516ba commit d321f85
Show file tree
Hide file tree
Showing 8 changed files with 514 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import React from 'react';
import { EuiIcon, EuiLink } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useHistory } from 'react-router-dom';
import { EuiBasicTable } from '@elastic/eui';
import { EuiBasicTableColumn } from '@elastic/eui';
Expand All @@ -31,7 +32,7 @@ interface Props<T> {
setSelectedSignificantTerm: (term: T | null) => void;
}

export function SignificantTermsTable<T extends SignificantTerm>({
export function CorrelationsTable<T extends SignificantTerm>({
significantTerms,
status,
cardinalityColumnName,
Expand All @@ -42,7 +43,10 @@ export function SignificantTermsTable<T extends SignificantTerm>({
{
width: '100px',
field: 'score',
name: 'Score',
name: i18n.translate(
'xpack.apm.correlations.correlationsTable.scoreLabel',
{ defaultMessage: 'Score' }
),
render: (_: any, term: T) => {
return <EuiCode>{Math.round(term.score)}</EuiCode>;
},
Expand All @@ -57,19 +61,31 @@ export function SignificantTermsTable<T extends SignificantTerm>({
},
{
field: 'fieldName',
name: 'Field name',
name: i18n.translate(
'xpack.apm.correlations.correlationsTable.fieldNameLabel',
{ defaultMessage: 'Field name' }
),
},
{
field: 'fieldValue',
name: 'Field value',
name: i18n.translate(
'xpack.apm.correlations.correlationsTable.fieldValueLabel',
{ defaultMessage: 'Field value' }
),
render: (_: any, term: T) => String(term.fieldValue).slice(0, 50),
},
{
width: '100px',
actions: [
{
name: 'Focus',
description: 'Focus on this term',
name: i18n.translate(
'xpack.apm.correlations.correlationsTable.filterLabel',
{ defaultMessage: 'Filter' }
),
description: i18n.translate(
'xpack.apm.correlations.correlationsTable.filterDescription',
{ defaultMessage: 'Filter by value' }
),
icon: 'magnifyWithPlus',
type: 'icon',
onClick: (term: T) => {
Expand All @@ -83,8 +99,14 @@ export function SignificantTermsTable<T extends SignificantTerm>({
},
},
{
name: 'Exclude',
description: 'Exclude this term',
name: i18n.translate(
'xpack.apm.correlations.correlationsTable.excludeLabel',
{ defaultMessage: 'Exclude' }
),
description: i18n.translate(
'xpack.apm.correlations.correlationsTable.excludeDescription',
{ defaultMessage: 'Filter out value' }
),
icon: 'magnifyWithMinus',
type: 'icon',
onClick: (term: T) => {
Expand All @@ -98,7 +120,10 @@ export function SignificantTermsTable<T extends SignificantTerm>({
},
},
],
name: 'Actions',
name: i18n.translate(
'xpack.apm.correlations.correlationsTable.actionsLabel',
{ defaultMessage: 'Actions' }
),
render: (_: any, term: T) => {
return (
<>
Expand Down Expand Up @@ -134,7 +159,9 @@ export function SignificantTermsTable<T extends SignificantTerm>({
return (
<EuiBasicTable
items={significantTerms ?? []}
noItemsMessage={status === FETCH_STATUS.LOADING ? 'Loading' : 'No data'}
noItemsMessage={
status === FETCH_STATUS.LOADING ? loadingText : noDataText
}
loading={status === FETCH_STATUS.LOADING}
columns={columns}
rowProps={(term) => {
Expand All @@ -146,3 +173,13 @@ export function SignificantTermsTable<T extends SignificantTerm>({
/>
);
}

const loadingText = i18n.translate(
'xpack.apm.correlations.correlationsTable.loadingText',
{ defaultMessage: 'Loading' }
);

const noDataText = i18n.translate(
'xpack.apm.correlations.correlationsTable.noDataText',
{ defaultMessage: 'No data' }
);
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ import {
EuiComboBox,
EuiAccordion,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher';
import { APIReturnType } from '../../../services/rest/createCallApmApi';
import { px } from '../../../style/variables';
import { SignificantTermsTable } from './SignificantTermsTable';
import { CorrelationsTable } from './correlations_table';
import { ChartContainer } from '../../shared/charts/chart_container';
import { useTheme } from '../../../hooks/use_theme';

type CorrelationsApiResponse = NonNullable<
APIReturnType<'GET /api/apm/correlations/failed_transactions'>
Expand Down Expand Up @@ -98,7 +100,11 @@ export function ErrorCorrelations() {
<EuiFlexGroup direction="column">
<EuiFlexItem>
<EuiTitle size="s">
<h4>Error rate over time</h4>
<h4>
{i18n.translate('xpack.apm.correlations.error.chart.title', {
defaultMessage: 'Error rate over time',
})}
</h4>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem>
Expand All @@ -109,10 +115,30 @@ export function ErrorCorrelations() {
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiAccordion id="accordion" buttonContent="Customize">
<CorrelationsTable
cardinalityColumnName={i18n.translate(
'xpack.apm.correlations.error.cardinalityColumnName',
{ defaultMessage: '# of failed transactions' }
)}
significantTerms={data?.significantTerms}
status={status}
setSelectedSignificantTerm={setSelectedSignificantTerm}
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiAccordion
id="accordion"
buttonContent={i18n.translate(
'xpack.apm.correlations.customize.buttonLabel',
{ defaultMessage: 'Customize fields' }
)}
>
<EuiComboBox
fullWidth={true}
placeholder="Select or create options"
placeholder={i18n.translate(
'xpack.apm.correlations.customize.fieldPlaceholder',
{ defaultMessage: 'Select or create options' }
)}
selectedOptions={fieldNames}
onChange={setFieldNames}
onCreateOption={(term) =>
Expand All @@ -121,14 +147,6 @@ export function ErrorCorrelations() {
/>
</EuiAccordion>
</EuiFlexItem>
<EuiFlexItem>
<SignificantTermsTable
cardinalityColumnName="# of failed transactions"
significantTerms={data?.significantTerms}
status={status}
setSelectedSignificantTerm={setSelectedSignificantTerm}
/>
</EuiFlexItem>
</EuiFlexGroup>
</>
);
Expand All @@ -143,6 +161,7 @@ function ErrorTimeseriesChart({
selectedSignificantTerm: SignificantTerm | null;
status: FETCH_STATUS;
}) {
const theme = useTheme();
const dateFormatter = timeFormatter('HH:mm:ss');

return (
Expand All @@ -164,7 +183,10 @@ function ErrorTimeseriesChart({
/>

<LineSeries
id="Overall error rate"
id={i18n.translate(
'xpack.apm.correlations.error.chart.overallErrorRateLabel',
{ defaultMessage: 'Overall error rate' }
)}
xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear}
xAccessor={'x'}
Expand All @@ -175,12 +197,15 @@ function ErrorTimeseriesChart({

{selectedSignificantTerm !== null ? (
<LineSeries
id="Error rate for selected term"
id={i18n.translate(
'xpack.apm.correlations.error.chart.selectedTermErrorRateLabel',
{ defaultMessage: 'Error rate for selected term' }
)}
xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear}
xAccessor={'x'}
yAccessors={['y']}
color="red"
color={theme.eui.euiColorAccent}
data={selectedSignificantTerm.timeseries}
curve={CurveType.CURVE_MONOTONE_X}
/>
Expand Down
95 changes: 81 additions & 14 deletions x-pack/plugins/apm/public/components/app/Correlations/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,55 @@ import {
EuiLink,
EuiCallOut,
EuiButton,
EuiTab,
EuiTabs,
EuiSpacer,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useHistory } from 'react-router-dom';
import { EuiSpacer } from '@elastic/eui';
import { isActivePlatinumLicense } from '../../../../common/license_check';
import { enableCorrelations } from '../../../../common/ui_settings_keys';
import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context';
import { LatencyCorrelations } from './LatencyCorrelations';
import { ErrorCorrelations } from './ErrorCorrelations';
import { LatencyCorrelations } from './latency_correlations';
import { ErrorCorrelations } from './error_correlations';
import { ThroughputCorrelations } from './throughput_correlations';
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
import { createHref } from '../../shared/Links/url_helpers';
import { useLicenseContext } from '../../../context/license/use_license_context';

const latencyTab = {
key: 'latency',
label: i18n.translate('xpack.apm.correlations.tabs.latencyLabel', {
defaultMessage: 'Latency',
}),
component: LatencyCorrelations,
};
const throughputTab = {
key: 'throughput',
label: i18n.translate('xpack.apm.correlations.tabs.throughputLabel', {
defaultMessage: 'Throughput',
}),
component: ThroughputCorrelations,
};
const errorRateTab = {
key: 'errorRate',
label: i18n.translate('xpack.apm.correlations.tabs.errorRateLabel', {
defaultMessage: 'Error rate',
}),
component: ErrorCorrelations,
};
const tabs = [latencyTab, throughputTab, errorRateTab];

export function Correlations() {
const { uiSettings } = useApmPluginContext().core;
const { urlParams } = useUrlParams();
const license = useLicenseContext();
const history = useHistory();
const [isFlyoutVisible, setIsFlyoutVisible] = useState(false);
const [currentTab, setCurrentTab] = useState(latencyTab.key);
const { component: TabContent } =
tabs.find((tab) => tab.key === currentTab) ?? latencyTab;

if (
!uiSettings.get(enableCorrelations) ||
!isActivePlatinumLicense(license)
Expand All @@ -48,8 +79,11 @@ export function Correlations() {
onClick={() => {
setIsFlyoutVisible(true);
}}
iconType="visTagCloud"
>
View correlations
{i18n.translate('xpack.apm.correlations.buttonLabel', {
defaultMessage: 'Explore correlations',
})}
</EuiButton>

<EuiSpacer size="s" />
Expand All @@ -63,19 +97,33 @@ export function Correlations() {
>
<EuiFlyoutHeader hasBorder aria-labelledby="correlations-flyout">
<EuiTitle>
<h2 id="correlations-flyout">Correlations</h2>
<h2 id="correlations-flyout">
{i18n.translate('xpack.apm.correlations.title', {
defaultMessage: 'Correlations',
})}
</h2>
</EuiTitle>
</EuiFlyoutHeader>
<EuiFlyoutBody>
{urlParams.kuery ? (
<>
<EuiCallOut size="m">
<span>Filtering by</span>
<span>
{i18n.translate(
'xpack.apm.correlations.filteringByLabel',
{ defaultMessage: 'Filtering by' }
)}
</span>
<EuiCode>{urlParams.kuery}</EuiCode>
<EuiLink
href={createHref(history, { query: { kuery: '' } })}
>
<EuiButtonEmpty iconType="cross">Clear</EuiButtonEmpty>
<EuiButtonEmpty iconType="cross">
{i18n.translate(
'xpack.apm.correlations.clearFiltersLabel',
{ defaultMessage: 'Clear' }
)}
</EuiButtonEmpty>
</EuiLink>
</EuiCallOut>
<EuiSpacer />
Expand All @@ -84,21 +132,40 @@ export function Correlations() {

<EuiCallOut
size="s"
title="Experimental"
title={i18n.translate(
'xpack.apm.correlations.experimentalWarning.title',
{ defaultMessage: 'Experimental' }
)}
color="warning"
iconType="alert"
>
<p>
Correlations is an experimental feature and in active
development. Bugs and surprises are to be expected but let us
know your feedback so we can improve it.
{i18n.translate(
'xpack.apm.correlations.experimentalWarning.text',
{
defaultMessage:
'Correlations is an experimental feature and in active development. Bugs and surprises are to be expected but let us know your feedback so we can improve it.',
}
)}
</p>
</EuiCallOut>

<EuiSpacer />

<LatencyCorrelations />
<ErrorCorrelations />
<EuiTabs>
{tabs.map(({ key, label }) => (
<EuiTab
key={key}
isSelected={key === currentTab}
onClick={() => {
setCurrentTab(key);
}}
>
{label}
</EuiTab>
))}
</EuiTabs>
<EuiSpacer />
<TabContent />
</EuiFlyoutBody>
</EuiFlyout>
</EuiPortal>
Expand Down
Loading

0 comments on commit d321f85

Please sign in to comment.