Ensure transactionType is used in overview (#85665)

* Ensure transactionType is used in overview

Fix the places where it was not being used:

- Transactions table
- Error rate chart
- Errors table

Also fix broken column sorting on transaction table.

* fix a sort

* test fix

* Snapshot update

* adds missing required param transactionType to API test

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Oliver Gupte <olivergupte@gmail.com>
This commit is contained in:
Nathan L Smith 2020-12-17 20:09:30 -06:00 committed by GitHub
parent 915ec196be
commit feecebf85e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 105 additions and 37 deletions

View file

@ -21,7 +21,8 @@ import * as useTransactionBreakdownHooks from '../../shared/charts/transaction_b
import { renderWithTheme } from '../../../utils/testHelpers';
import { ServiceOverview } from './';
import { waitFor } from '@testing-library/dom';
import * as callApmApi from '../../../services/rest/createCallApmApi';
import * as callApmApiModule from '../../../services/rest/createCallApmApi';
import * as useApmServiceContextHooks from '../../../context/apm_service/use_apm_service_context';
const KibanaReactContext = createKibanaReactContext({
usageCollection: { reportUiCounter: () => {} },
@ -56,6 +57,13 @@ function Wrapper({ children }: { children?: ReactNode }) {
describe('ServiceOverview', () => {
it('renders', async () => {
jest
.spyOn(useApmServiceContextHooks, 'useApmServiceContext')
.mockReturnValue({
agentName: 'java',
transactionType: 'request',
transactionTypes: ['request'],
});
jest
.spyOn(useAnnotationsHooks, 'useAnnotationsContext')
.mockReturnValue({ annotations: [] });
@ -78,17 +86,23 @@ describe('ServiceOverview', () => {
isAggregationAccurate: true,
},
'GET /api/apm/services/{serviceName}/dependencies': [],
// eslint-disable-next-line @typescript-eslint/naming-convention
'GET /api/apm/services/{serviceName}/service_overview_instances': [],
};
jest.spyOn(callApmApi, 'createCallApmApi').mockImplementation(() => {});
jest
.spyOn(callApmApiModule, 'createCallApmApi')
.mockImplementation(() => {});
jest.spyOn(callApmApi, 'callApmApi').mockImplementation(({ endpoint }) => {
const response = calls[endpoint as keyof typeof calls];
const callApmApi = jest
.spyOn(callApmApiModule, 'callApmApi')
.mockImplementation(({ endpoint }) => {
const response = calls[endpoint as keyof typeof calls];
return response
? Promise.resolve(response)
: Promise.reject(`Response for ${endpoint} is not defined`);
});
return response
? Promise.resolve(response)
: Promise.reject(`Response for ${endpoint} is not defined`);
});
jest
.spyOn(useTransactionBreakdownHooks, 'useTransactionBreakdown')
.mockReturnValue({
@ -105,9 +119,7 @@ describe('ServiceOverview', () => {
);
await waitFor(() =>
expect(callApmApi.callApmApi).toHaveBeenCalledTimes(
Object.keys(calls).length
)
expect(callApmApi).toHaveBeenCalledTimes(Object.keys(calls).length)
);
expect((await findAllByText('Latency')).length).toBeGreaterThan(0);

View file

@ -13,6 +13,7 @@ import {
import { i18n } from '@kbn/i18n';
import React, { useState } from 'react';
import { asInteger } 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, useFetcher } from '../../../../hooks/use_fetcher';
import { callApmApi } from '../../../../services/rest/createCallApmApi';
@ -54,7 +55,7 @@ export function ServiceOverviewErrorsTable({ serviceName }: Props) {
urlParams: { start, end },
uiFilters,
} = useUrlParams();
const { transactionType } = useApmServiceContext();
const [tableOptions, setTableOptions] = useState<{
pageIndex: number;
sort: {
@ -141,7 +142,7 @@ export function ServiceOverviewErrorsTable({ serviceName }: Props) {
},
status,
} = useFetcher(() => {
if (!start || !end) {
if (!start || !end || !transactionType) {
return;
}
@ -158,6 +159,7 @@ export function ServiceOverviewErrorsTable({ serviceName }: Props) {
pageIndex: tableOptions.pageIndex,
sortField: tableOptions.sort.field,
sortDirection: tableOptions.sort.direction,
transactionType,
},
},
}).then((response) => {
@ -181,6 +183,7 @@ export function ServiceOverviewErrorsTable({ serviceName }: Props) {
tableOptions.pageIndex,
tableOptions.sort.field,
tableOptions.sort.direction,
transactionType,
]);
const {

View file

@ -28,14 +28,15 @@ import {
callApmApi,
} from '../../../../services/rest/createCallApmApi';
import { px, unit } from '../../../../style/variables';
import { SparkPlot } from '../../../shared/charts/spark_plot';
import { ImpactBar } from '../../../shared/ImpactBar';
import { TransactionDetailLink } from '../../../shared/Links/apm/TransactionDetailLink';
import { TransactionOverviewLink } from '../../../shared/Links/apm/TransactionOverviewLink';
import { TableFetchWrapper } from '../../../shared/table_fetch_wrapper';
import { TableLinkFlexItem } from '../table_link_flex_item';
import { SparkPlot } from '../../../shared/charts/spark_plot';
import { ImpactBar } from '../../../shared/ImpactBar';
import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context';
import { TruncateWithTooltip } from '../../../shared/truncate_with_tooltip';
import { ServiceOverviewTableContainer } from '../service_overview_table_container';
import { TableLinkFlexItem } from '../table_link_flex_item';
type ServiceTransactionGroupItem = ValuesType<
APIReturnType<'GET /api/apm/services/{serviceName}/transactions/groups/overview'>['transactionGroups']
@ -45,7 +46,7 @@ interface Props {
serviceName: string;
}
type SortField = 'latency' | 'throughput' | 'errorRate' | 'impact';
type SortField = 'name' | 'latency' | 'throughput' | 'errorRate' | 'impact';
type SortDirection = 'asc' | 'desc';
const PAGE_SIZE = 5;
@ -85,7 +86,9 @@ function getLatencyAggregationTypeLabel(
}
}
export function ServiceOverviewTransactionsTable({ serviceName }: Props) {
export function ServiceOverviewTransactionsTable(props: Props) {
const { serviceName } = props;
const { transactionType } = useApmServiceContext();
const latencyAggregationType = useLatencyAggregationType();
const {
uiFilters,
@ -114,7 +117,7 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) {
},
status,
} = useFetcher(() => {
if (!start || !end || !latencyAggregationType) {
if (!start || !end || !latencyAggregationType || !transactionType) {
return;
}
@ -132,6 +135,7 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) {
pageIndex: tableOptions.pageIndex,
sortField: tableOptions.sort.field,
sortDirection: tableOptions.sort.direction,
transactionType,
latencyAggregationType,
},
},
@ -156,6 +160,7 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) {
tableOptions.pageIndex,
tableOptions.sort.field,
tableOptions.sort.direction,
transactionType,
latencyAggregationType,
]);
@ -174,7 +179,7 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) {
defaultMessage: 'Name',
}
),
render: (_, { name, transactionType }) => {
render: (_, { name, transactionType: type }) => {
return (
<TruncateWithTooltip
text={name}
@ -182,7 +187,7 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) {
<TransactionDetailLink
serviceName={serviceName}
transactionName={name}
transactionType={transactionType}
transactionType={type}
>
{name}
</TransactionDetailLink>
@ -227,7 +232,7 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) {
},
},
{
field: 'error_rate',
field: 'errorRate',
name: i18n.translate(
'xpack.apm.serviceOverview.transactionsTableColumnErrorRate',
{

View file

@ -14,6 +14,7 @@ import { useTheme } from '../../../../hooks/use_theme';
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
import { callApmApi } from '../../../../services/rest/createCallApmApi';
import { TimeseriesChart } from '../timeseries_chart';
import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context';
function yLabelFormat(y?: number | null) {
return asPercent(y || 0, 1);
@ -31,8 +32,8 @@ export function TransactionErrorRateChart({
const theme = useTheme();
const { serviceName } = useParams<{ serviceName?: string }>();
const { urlParams, uiFilters } = useUrlParams();
const { start, end, transactionType, transactionName } = urlParams;
const { transactionType } = useApmServiceContext();
const { start, end, transactionName } = urlParams;
const { data, status } = useFetcher(() => {
if (serviceName && start && end) {

View file

@ -15,6 +15,7 @@ import {
ERROR_GROUP_ID,
ERROR_LOG_MESSAGE,
SERVICE_NAME,
TRANSACTION_TYPE,
} from '../../../../common/elasticsearch_fieldnames';
import { Setup, SetupTimeRange } from '../../helpers/setup_request';
import { getBucketSize } from '../../helpers/get_bucket_size';
@ -32,6 +33,7 @@ export async function getServiceErrorGroups({
pageIndex,
sortDirection,
sortField,
transactionType,
}: {
serviceName: string;
setup: Setup & SetupTimeRange;
@ -40,6 +42,7 @@ export async function getServiceErrorGroups({
numBuckets: number;
sortDirection: 'asc' | 'desc';
sortField: 'name' | 'last_seen' | 'occurrences';
transactionType: string;
}) {
const { apmEventClient, start, end, esFilter } = setup;
@ -55,6 +58,7 @@ export async function getServiceErrorGroups({
bool: {
filter: [
{ term: { [SERVICE_NAME]: serviceName } },
{ term: { [TRANSACTION_TYPE]: transactionType } },
{ range: rangeFilter(start, end) },
...esFilter,
],
@ -127,6 +131,7 @@ export async function getServiceErrorGroups({
filter: [
{ terms: { [ERROR_GROUP_ID]: sortedErrorGroupIds } },
{ term: { [SERVICE_NAME]: serviceName } },
{ term: { [TRANSACTION_TYPE]: transactionType } },
{ range: rangeFilter(start, end) },
...esFilter,
],

View file

@ -38,6 +38,7 @@ export async function getTimeseriesDataForTransactionGroups({
searchAggregatedTransactions,
size,
numBuckets,
transactionType,
latencyAggregationType,
}: {
apmEventClient: APMEventClient;
@ -49,6 +50,7 @@ export async function getTimeseriesDataForTransactionGroups({
searchAggregatedTransactions: boolean;
size: number;
numBuckets: number;
transactionType: string;
latencyAggregationType: LatencyAggregationType;
}) {
const { intervalString } = getBucketSize({ start, end, numBuckets });
@ -72,6 +74,7 @@ export async function getTimeseriesDataForTransactionGroups({
filter: [
{ terms: { [TRANSACTION_NAME]: transactionNames } },
{ term: { [SERVICE_NAME]: serviceName } },
{ term: { [TRANSACTION_TYPE]: transactionType } },
{ range: rangeFilter(start, end) },
...esFilter,
],

View file

@ -14,6 +14,7 @@ import {
EVENT_OUTCOME,
SERVICE_NAME,
TRANSACTION_NAME,
TRANSACTION_TYPE,
} from '../../../../common/elasticsearch_fieldnames';
import {
getProcessorEventForAggregatedTransactions,
@ -26,6 +27,7 @@ import {
} from '../../helpers/latency_aggregation_type';
export type ServiceOverviewTransactionGroupSortField =
| 'name'
| 'latency'
| 'throughput'
| 'errorRate'
@ -46,6 +48,7 @@ export async function getTransactionGroupsForPage({
sortDirection,
pageIndex,
size,
transactionType,
latencyAggregationType,
}: {
apmEventClient: APMEventClient;
@ -58,6 +61,7 @@ export async function getTransactionGroupsForPage({
sortDirection: 'asc' | 'desc';
pageIndex: number;
size: number;
transactionType: string;
latencyAggregationType: LatencyAggregationType;
}) {
const field = getTransactionDurationFieldForAggregatedTransactions(
@ -78,6 +82,7 @@ export async function getTransactionGroupsForPage({
bool: {
filter: [
{ term: { [SERVICE_NAME]: serviceName } },
{ term: { [TRANSACTION_TYPE]: transactionType } },
{ range: rangeFilter(start, end) },
...esFilter,
],

View file

@ -22,6 +22,7 @@ export async function getServiceTransactionGroups({
sortDirection,
sortField,
searchAggregatedTransactions,
transactionType,
latencyAggregationType,
}: {
serviceName: string;
@ -32,6 +33,7 @@ export async function getServiceTransactionGroups({
sortDirection: 'asc' | 'desc';
sortField: ServiceOverviewTransactionGroupSortField;
searchAggregatedTransactions: boolean;
transactionType: string;
latencyAggregationType: LatencyAggregationType;
}) {
const { apmEventClient, start, end, esFilter } = setup;
@ -51,6 +53,7 @@ export async function getServiceTransactionGroups({
sortDirection,
size,
searchAggregatedTransactions,
transactionType,
latencyAggregationType,
});
@ -66,6 +69,7 @@ export async function getServiceTransactionGroups({
serviceName,
size,
transactionNames,
transactionType,
latencyAggregationType,
});

View file

@ -257,6 +257,7 @@ export const serviceErrorGroupsRoute = createRoute({
t.literal('occurrences'),
t.literal('name'),
]),
transactionType: t.string,
}),
]),
}),
@ -266,7 +267,14 @@ export const serviceErrorGroupsRoute = createRoute({
const {
path: { serviceName },
query: { size, numBuckets, pageIndex, sortDirection, sortField },
query: {
numBuckets,
pageIndex,
size,
sortDirection,
sortField,
transactionType,
},
} = context.params;
return getServiceErrorGroups({
serviceName,
@ -276,6 +284,7 @@ export const serviceErrorGroupsRoute = createRoute({
pageIndex,
sortDirection,
sortField,
transactionType,
});
},
});

View file

@ -77,11 +77,13 @@ export const transactionGroupsOverviewRoute = createRoute({
pageIndex: toNumberRt,
sortDirection: t.union([t.literal('asc'), t.literal('desc')]),
sortField: t.union([
t.literal('name'),
t.literal('latency'),
t.literal('throughput'),
t.literal('errorRate'),
t.literal('impact'),
]),
transactionType: t.string,
latencyAggregationType: latencyAggregationTypeRt,
}),
]),
@ -99,12 +101,13 @@ export const transactionGroupsOverviewRoute = createRoute({
const {
path: { serviceName },
query: {
size,
latencyAggregationType,
numBuckets,
pageIndex,
size,
sortDirection,
sortField,
latencyAggregationType,
transactionType,
},
} = context.params;
@ -116,6 +119,7 @@ export const transactionGroupsOverviewRoute = createRoute({
size,
sortDirection,
sortField,
transactionType,
numBuckets,
latencyAggregationType: latencyAggregationType as LatencyAggregationType,
});

View file

@ -30,6 +30,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
pageIndex: 0,
sortDirection: 'desc',
sortField: 'occurrences',
transactionType: 'request',
})}`
);
@ -57,6 +58,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
pageIndex: 0,
sortDirection: 'desc',
sortField: 'occurrences',
transactionType: 'request',
})}`
);
@ -114,6 +116,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
pageIndex: 0,
sortDirection: 'desc',
sortField: 'occurrences',
transactionType: 'request',
})}`
);
@ -135,6 +138,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
pageIndex: 0,
sortDirection: 'desc',
sortField: 'occurrences',
transactionType: 'request',
})}`
);
@ -156,6 +160,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
pageIndex: 0,
sortDirection: 'desc',
sortField: 'last_seen',
transactionType: 'request',
})}`
);
@ -179,6 +184,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
pageIndex: 0,
sortDirection: 'desc',
sortField: 'occurrences',
transactionType: 'request',
})}`
);
@ -203,6 +209,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
pageIndex,
sortDirection: 'desc',
sortField: 'occurrences',
transactionType: 'request',
})}`
);

View file

@ -5,6 +5,7 @@
*/
import expect from '@kbn/expect';
import { first, last } from 'lodash';
import { format } from 'url';
import archives_metadata from '../../../common/archives_metadata';
import { FtrProviderContext } from '../../../common/ftr_provider_context';
@ -13,19 +14,21 @@ export default function ApiTest({ getService }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const archiveName = 'apm_8.0.0';
const metadata = archives_metadata[archiveName];
// url parameters
const start = encodeURIComponent(metadata.start);
const end = encodeURIComponent(metadata.end);
const uiFilters = encodeURIComponent(JSON.stringify({}));
const { start, end } = archives_metadata[archiveName];
const uiFilters = '{}';
const transactionType = 'request';
describe('Error rate', () => {
const url = format({
pathname: '/api/apm/services/opbeans-java/transactions/charts/error_rate',
query: { start, end, uiFilters, transactionType },
});
describe('when data is not loaded', () => {
it('handles the empty state', async () => {
const response = await supertest.get(
`/api/apm/services/opbeans-java/transactions/charts/error_rate?start=${start}&end=${end}&uiFilters=${uiFilters}`
);
const response = await supertest.get(url);
expect(response.status).to.be(200);
expect(response.body.noHits).to.be(true);
@ -34,6 +37,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
expect(response.body.average).to.be(null);
});
});
describe('when data is loaded', () => {
before(() => esArchiver.load(archiveName));
after(() => esArchiver.unload(archiveName));
@ -43,10 +47,9 @@ export default function ApiTest({ getService }: FtrProviderContext) {
transactionErrorRate: Array<{ x: number; y: number | null }>;
average: number;
};
before(async () => {
const response = await supertest.get(
`/api/apm/services/opbeans-java/transactions/charts/error_rate?start=${start}&end=${end}&uiFilters=${uiFilters}`
);
const response = await supertest.get(url);
errorRateResponse = response.body;
});

View file

@ -33,6 +33,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
sortDirection: 'desc',
sortField: 'impact',
latencyAggregationType: 'avg',
transactionType: 'request',
},
})
);
@ -63,6 +64,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
pageIndex: 0,
sortDirection: 'desc',
sortField: 'impact',
transactionType: 'request',
latencyAggregationType: 'avg',
},
})
@ -140,6 +142,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
pageIndex: 0,
sortDirection: 'desc',
sortField: 'impact',
transactionType: 'request',
latencyAggregationType: 'avg',
},
})
@ -165,6 +168,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
pageIndex: 0,
sortDirection: 'desc',
sortField: 'impact',
transactionType: 'request',
latencyAggregationType: 'avg',
},
})
@ -190,6 +194,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
pageIndex: 0,
sortDirection: 'desc',
sortField: 'latency',
transactionType: 'request',
latencyAggregationType: 'avg',
},
})
@ -217,6 +222,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
pageIndex: 0,
sortDirection: 'desc',
sortField: 'impact',
transactionType: 'request',
latencyAggregationType: 'avg',
},
})
@ -245,6 +251,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
pageIndex,
sortDirection: 'desc',
sortField: 'impact',
transactionType: 'request',
latencyAggregationType: 'avg',
},
})