Skip to content

Commit

Permalink
[ML] Replace APM error rate table with failed transactions correlatio…
Browse files Browse the repository at this point in the history
…ns (#108441) (#109000)

* [ML] Refactor with new table

* [ML] Fix types, rename var

* [ML] Remove duplicate action columns

* [ML] Finish renaming for consistency

* [ML] Add failure correlations help popover

* [ML] Add failure correlations help popover

* [ML] Extend correlation help

* Update message

* [ML] Delete old legacy correlations pages

* [ML] Address comments, rename

* [ML] Revert deletion of latency_correlations.tsx

* [ML] Add unit test for getFailedTransactionsCorrelationImpactLabel

* [ML] Rename & fix types

* [ML] Fix logic to note include 0.02 threshold

* [ML] Refactor to use state handler

* [ML] Fix hardcoded index, columns, popover

* [ML] Replace failed transaction tab

* [ML] Fix unused translations

* [ML] Delete empty files

* [ML] Move beta badge to be inside tab content

Co-authored-by: lcawl <lcawley@elastic.co>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>

Co-authored-by: Quynh Nguyen <43350163+qn895@users.noreply.github.com>
Co-authored-by: lcawl <lcawley@elastic.co>
  • Loading branch information
3 people committed Aug 17, 2021
1 parent 62cad9b commit b6d14af
Show file tree
Hide file tree
Showing 22 changed files with 1,274 additions and 506 deletions.
@@ -0,0 +1,32 @@
/*
* 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';

export const FAILED_TRANSACTIONS_CORRELATION_SEARCH_STRATEGY =
'apmFailedTransactionsCorrelationsSearchStrategy';

export const FAILED_TRANSACTIONS_IMPACT_THRESHOLD = {
HIGH: i18n.translate(
'xpack.apm.correlations.failedTransactions.highImpactText',
{
defaultMessage: 'High',
}
),
MEDIUM: i18n.translate(
'xpack.apm.correlations.failedTransactions.mediumImpactText',
{
defaultMessage: 'Medium',
}
),
LOW: i18n.translate(
'xpack.apm.correlations.failedTransactions.lowImpactText',
{
defaultMessage: 'Low',
}
),
} as const;
@@ -0,0 +1,25 @@
/*
* 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 { FAILED_TRANSACTIONS_IMPACT_THRESHOLD } from './constants';

export interface FailedTransactionsCorrelationValue {
key: string;
doc_count: number;
bg_count: number;
score: number;
pValue: number | null;
fieldName: string;
fieldValue: string;
}

export type FailureCorrelationImpactThreshold = typeof FAILED_TRANSACTIONS_IMPACT_THRESHOLD[keyof typeof FAILED_TRANSACTIONS_IMPACT_THRESHOLD];

export interface CorrelationsTerm {
fieldName: string;
fieldValue: string;
}
Expand Up @@ -7,65 +7,47 @@

import React, { useCallback, useMemo, useState } from 'react';
import { debounce } from 'lodash';
import {
EuiIcon,
EuiLink,
EuiBasicTable,
EuiBasicTableColumn,
EuiToolTip,
} from '@elastic/eui';
import { EuiBasicTable, EuiBasicTableColumn } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useHistory } from 'react-router-dom';
import { asInteger, asPercent } from '../../../../common/utils/formatters';
import { APIReturnType } from '../../../services/rest/createCallApmApi';
import { FETCH_STATUS } from '../../../hooks/use_fetcher';
import { createHref, push } from '../../shared/Links/url_helpers';
import { ImpactBar } from '../../shared/ImpactBar';
import { useUiTracker } from '../../../../../observability/public';
import { useTheme } from '../../../hooks/use_theme';
import { CorrelationsTerm } from '../../../../common/search_strategies/failure_correlations/types';

const PAGINATION_SIZE_OPTIONS = [5, 10, 20, 50];
type CorrelationsApiResponse =
| APIReturnType<'GET /api/apm/correlations/errors/failed_transactions'>
| APIReturnType<'GET /api/apm/correlations/latency/slow_transactions'>;

export type SignificantTerm = CorrelationsApiResponse['significantTerms'][0];

export type SelectedSignificantTerm = Pick<
SignificantTerm,
export type SelectedCorrelationTerm<T extends CorrelationsTerm> = Pick<
T,
'fieldName' | 'fieldValue'
>;

interface Props<T> {
significantTerms?: T[];
status: FETCH_STATUS;
percentageColumnName?: string;
setSelectedSignificantTerm: (term: SelectedSignificantTerm | null) => void;
setSelectedSignificantTerm: (term: T | null) => void;
selectedTerm?: { fieldName: string; fieldValue: string };
onFilter: () => void;
columns?: Array<EuiBasicTableColumn<T>>;
onFilter?: () => void;
columns: Array<EuiBasicTableColumn<T>>;
}

export function CorrelationsTable<T extends SignificantTerm>({
export function CorrelationsTable<T extends CorrelationsTerm>({
significantTerms,
status,
percentageColumnName,
setSelectedSignificantTerm,
onFilter,
columns,
selectedTerm,
}: Props<T>) {
const euiTheme = useTheme();
const trackApmEvent = useUiTracker({ app: 'apm' });
const trackSelectSignificantTerm = useCallback(
const trackSelectSignificantCorrelationTerm = useCallback(
() =>
debounce(
() => trackApmEvent({ metric: 'select_significant_term' }),
1000
),
[trackApmEvent]
);
const history = useHistory();

const [pageIndex, setPageIndex] = useState(0);
const [pageSize, setPageSize] = useState(10);
Expand All @@ -92,153 +74,19 @@ export function CorrelationsTable<T extends SignificantTerm>({
setPageSize(size);
}, []);

const tableColumns: Array<EuiBasicTableColumn<T>> = columns ?? [
{
width: '116px',
field: 'impact',
name: i18n.translate(
'xpack.apm.correlations.correlationsTable.impactLabel',
{ defaultMessage: 'Impact' }
),
render: (_: any, term: T) => {
return <ImpactBar size="m" value={term.impact * 100} />;
},
},
{
field: 'percentage',
name:
percentageColumnName ??
i18n.translate(
'xpack.apm.correlations.correlationsTable.percentageLabel',
{ defaultMessage: 'Percentage' }
),
render: (_: any, term: T) => {
return (
<EuiToolTip
position="right"
content={`${asInteger(term.valueCount)} / ${asInteger(
term.fieldCount
)}`}
>
<>{asPercent(term.valueCount, term.fieldCount)}</>
</EuiToolTip>
);
},
},
{
field: 'fieldName',
name: i18n.translate(
'xpack.apm.correlations.correlationsTable.fieldNameLabel',
{ defaultMessage: 'Field name' }
),
},
{
field: 'fieldValue',
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: i18n.translate(
'xpack.apm.correlations.correlationsTable.filterLabel',
{ defaultMessage: 'Filter' }
),
description: i18n.translate(
'xpack.apm.correlations.correlationsTable.filterDescription',
{ defaultMessage: 'Filter by value' }
),
icon: 'plusInCircle',
type: 'icon',
onClick: (term: T) => {
push(history, {
query: {
kuery: `${term.fieldName}:"${encodeURIComponent(
term.fieldValue
)}"`,
},
});
onFilter();
trackApmEvent({ metric: 'correlations_term_include_filter' });
},
},
{
name: i18n.translate(
'xpack.apm.correlations.correlationsTable.excludeLabel',
{ defaultMessage: 'Exclude' }
),
description: i18n.translate(
'xpack.apm.correlations.correlationsTable.excludeDescription',
{ defaultMessage: 'Filter out value' }
),
icon: 'minusInCircle',
type: 'icon',
onClick: (term: T) => {
push(history, {
query: {
kuery: `not ${term.fieldName}:"${encodeURIComponent(
term.fieldValue
)}"`,
},
});
onFilter();
trackApmEvent({ metric: 'correlations_term_exclude_filter' });
},
},
],
name: i18n.translate(
'xpack.apm.correlations.correlationsTable.actionsLabel',
{ defaultMessage: 'Filter' }
),
render: (_: any, term: T) => {
return (
<>
<EuiLink
href={createHref(history, {
query: {
kuery: `${term.fieldName}:"${encodeURIComponent(
term.fieldValue
)}"`,
},
})}
>
<EuiIcon type="magnifyWithPlus" />
</EuiLink>
&nbsp;/&nbsp;
<EuiLink
href={createHref(history, {
query: {
kuery: `not ${term.fieldName}:"${encodeURIComponent(
term.fieldValue
)}"`,
},
})}
>
<EuiIcon type="magnifyWithMinus" />
</EuiLink>
</>
);
},
},
];

return (
<EuiBasicTable
items={pageOfItems ?? []}
noItemsMessage={
status === FETCH_STATUS.LOADING ? loadingText : noDataText
}
loading={status === FETCH_STATUS.LOADING}
columns={tableColumns}
columns={columns}
rowProps={(term) => {
return {
onMouseEnter: () => {
setSelectedSignificantTerm(term);
trackSelectSignificantTerm();
trackSelectSignificantCorrelationTerm();
},
onMouseLeave: () => setSelectedSignificantTerm(null),
style:
Expand Down

0 comments on commit b6d14af

Please sign in to comment.