Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[APM] Add error rates to Service Map popovers #69520

Merged
merged 39 commits into from
Jul 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
f07d9fb
[APM] Add error rates to Service Map popovers
smith Jun 16, 2020
8fa2b55
Remove unused import from chart
smith Jun 18, 2020
4ebfd44
Merge remote-tracking branch 'upstream/master' into nls/pop-error-rate
smith Jun 23, 2020
ec1d918
Merge remote-tracking branch 'upstream/master' into nls/pop-error-rate
smith Jun 23, 2020
511e780
Merge remote-tracking branch 'upstream/master' into nls/pop-error-rate
smith Jun 24, 2020
59fe92b
Merge remote-tracking branch 'upstream/master' into nls/pop-error-rate
smith Jun 25, 2020
1edccf6
Merge remote-tracking branch 'upstream/master' into nls/pop-error-rate
smith Jun 25, 2020
d9082ff
Rename metrics functions to stats functions; remove groupid param; fi…
smith Jun 25, 2020
e9054c2
Add popover story
smith Jun 26, 2020
c5ebe05
exclude more proptables
smith Jun 26, 2020
b064e8f
Merge remote-tracking branch 'upstream/master' into nls/pop-error-rate
smith Jun 26, 2020
0fae08e
Rename things
smith Jun 26, 2020
25d6bee
Merge remote-tracking branch 'upstream/master' into nls/pop-error-rate
smith Jun 26, 2020
5c89dd7
Merge remote-tracking branch 'upstream/master' into nls/pop-error-rate
smith Jun 26, 2020
63b0798
Merge remote-tracking branch 'upstream/master' into nls/pop-error-rate
smith Jun 29, 2020
3fd7ec3
Env changes to stats
smith Jun 29, 2020
9de9e84
Merge remote-tracking branch 'upstream/master' into nls/pop-error-rate
smith Jun 29, 2020
fa0aa61
more env changes
smith Jun 29, 2020
be9813d
Revert change to get_service_map
smith Jun 29, 2020
3ffe9ea
reorder imports
smith Jun 29, 2020
5e41800
Broken thing
smith Jun 29, 2020
f198bd9
Revert "Broken thing"
smith Jun 29, 2020
2eb50c2
more
smith Jun 30, 2020
1caa6ff
Merge remote-tracking branch 'upstream/master' into nls/pop-error-rate
smith Jun 30, 2020
e39dfba
add test
smith Jun 30, 2020
51e3ce4
Merge remote-tracking branch 'upstream/master' into nls/pop-error-rate
smith Jun 30, 2020
49ef805
add api integration test
smith Jun 30, 2020
543b651
Merge remote-tracking branch 'upstream/master' into nls/pop-error-rate
smith Jul 6, 2020
e1899f4
update mean import
smith Jul 6, 2020
06fd500
fix import
smith Jul 6, 2020
de7e9e3
i18n fix
smith Jul 6, 2020
fc46446
Merge branch 'master' of github.com:elastic/kibana into nls/pop-error…
cauemarcondes Jul 14, 2020
a161a36
getting error rate
cauemarcondes Jul 14, 2020
f7965a1
returning transaction error rate
cauemarcondes Jul 14, 2020
ebc0b86
addressing pr comments
cauemarcondes Jul 14, 2020
c78892b
Remove unused import
smith Jul 14, 2020
37ed6be
Merge remote-tracking branch 'upstream/master' into nls/pop-error-rate
smith Jul 15, 2020
c623b90
Fix failing api test
smith Jul 15, 2020
4a0a421
Merge branch 'master' into nls/pop-error-rate
elasticmachine Jul 15, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions x-pack/plugins/apm/common/service_map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ export interface Connection {
destination: ConnectionNode;
}

export interface ServiceNodeMetrics {
export interface ServiceNodeStats {
avgMemoryUsage: number | null;
avgCpuUsage: number | null;
transactionStats: {
avgTransactionDuration: number | null;
avgRequestsPerMinute: number | null;
};
avgErrorsPerMinute: number | null;
avgErrorRate: number | null;
}

export function isValidPlatinumLicense(license: ILicense) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import cytoscape from 'cytoscape';
import React, { MouseEvent } from 'react';
import { Buttons } from './Buttons';
import { Info } from './Info';
import { ServiceMetricFetcher } from './ServiceMetricFetcher';
import { ServiceStatsFetcher } from './ServiceStatsFetcher';
import { popoverWidth } from '../cytoscapeOptions';

interface ContentsProps {
Expand Down Expand Up @@ -70,7 +70,7 @@ export function Contents({
</FlexColumnItem>
<FlexColumnItem>
{isService ? (
<ServiceMetricFetcher
<ServiceStatsFetcher
serviceName={selectedNodeServiceName}
serviceAnomalyStats={selectedNodeData.serviceAnomalyStats}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ export function Info(data: InfoProps) {

const listItems = [
{
title: i18n.translate('xpack.apm.serviceMap.typePopoverMetric', {
title: i18n.translate('xpack.apm.serviceMap.typePopoverStat', {
defaultMessage: 'Type',
}),
description: type,
},
{
title: i18n.translate('xpack.apm.serviceMap.subtypePopoverMetric', {
title: i18n.translate('xpack.apm.serviceMap.subtypePopoverStat', {
defaultMessage: 'Subtype',
}),
description: subtype,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,128 @@
*/

import { storiesOf } from '@storybook/react';
import cytoscape from 'cytoscape';
import { HttpSetup } from 'kibana/public';
import React from 'react';
import { ServiceMetricList } from './ServiceMetricList';
import { EuiThemeProvider } from '../../../../../../observability/public';
import { MockApmPluginContextWrapper } from '../../../../context/ApmPluginContext/MockApmPluginContext';
import { MockUrlParamsContextProvider } from '../../../../context/UrlParamsContext/MockUrlParamsContextProvider';
import { createCallApmApi } from '../../../../services/rest/createCallApmApi';
import { CytoscapeContext } from '../Cytoscape';
import { Popover } from './';
import { ServiceStatsList } from './ServiceStatsList';

storiesOf('app/ServiceMap/Popover/ServiceMetricList', module)
.add('example', () => (
<ServiceMetricList
avgErrorsPerMinute={15.738888706725826}
transactionStats={{
avgTransactionDuration: 61634.38905590272,
storiesOf('app/ServiceMap/Popover', module)
.addDecorator((storyFn) => {
const node = {
data: { id: 'example service', 'service.name': 'example service' },
};
const cy = cytoscape({ elements: [node] });
const httpMock = ({
get: async () => ({
avgCpuUsage: 0.32809666568309237,
avgErrorRate: 0.556068173242986,
avgMemoryUsage: 0.5504868173242986,
avgRequestsPerMinute: 164.47222031860858,
}}
avgCpuUsage={0.32809666568309237}
avgMemoryUsage={0.5504868173242986}
/>
))
.add('some null values', () => (
<ServiceMetricList
avgErrorsPerMinute={7.615972134074397}
transactionStats={{
avgTransactionDuration: 238792.54809512055,
avgRequestsPerMinute: 8.439583235652972,
}}
avgCpuUsage={null}
avgMemoryUsage={null}
/>
))
.add('all null values', () => (
<ServiceMetricList
avgErrorsPerMinute={null}
transactionStats={{
avgTransactionDuration: null,
avgRequestsPerMinute: null,
}}
avgCpuUsage={null}
avgMemoryUsage={null}
/>
));
avgTransactionDuration: 61634.38905590272,
}),
} as unknown) as HttpSetup;

createCallApmApi(httpMock);

setImmediate(() => {
cy.$('example service').select();
});

return (
<EuiThemeProvider>
<MockUrlParamsContextProvider>
<MockApmPluginContextWrapper>
<CytoscapeContext.Provider value={cy}>
<div style={{ height: 325 }}>{storyFn()}</div>
</CytoscapeContext.Provider>
</MockApmPluginContextWrapper>
</MockUrlParamsContextProvider>
</EuiThemeProvider>
);
})
.add(
'example',
() => {
return <Popover />;
},
{
info: {
propTablesExclude: [
CytoscapeContext.Provider,
MockApmPluginContextWrapper,
MockUrlParamsContextProvider,
EuiThemeProvider,
],
source: false,
},
}
);

storiesOf('app/ServiceMap/Popover/ServiceStatsList', module)
.addDecorator((storyFn) => <EuiThemeProvider>{storyFn()}</EuiThemeProvider>)
.add(
'example',
() => (
<ServiceStatsList
avgCpuUsage={0.32809666568309237}
avgMemoryUsage={0.5504868173242986}
transactionStats={{
avgRequestsPerMinute: 164.47222031860858,
avgTransactionDuration: 61634.38905590272,
}}
avgErrorRate={0.556068173242986}
/>
),
{ info: { propTablesExclude: [EuiThemeProvider] } }
)
.add(
'loading',
() => (
<ServiceStatsList
avgCpuUsage={null}
avgErrorRate={null}
avgMemoryUsage={null}
transactionStats={{
avgRequestsPerMinute: null,
avgTransactionDuration: null,
}}
/>
),
{ info: { propTablesExclude: [EuiThemeProvider] } }
)
.add(
'some null values',
() => (
<ServiceStatsList
avgCpuUsage={null}
avgErrorRate={0.615972134074397}
avgMemoryUsage={null}
transactionStats={{
avgRequestsPerMinute: 8.439583235652972,
avgTransactionDuration: 238792.54809512055,
}}
/>
),
{ info: { propTablesExclude: [EuiThemeProvider] } }
)
.add(
'all null values',
() => (
<ServiceStatsList
avgCpuUsage={null}
avgErrorRate={null}
avgMemoryUsage={null}
transactionStats={{
avgRequestsPerMinute: null,
avgTransactionDuration: null,
}}
/>
),
{ info: { propTablesExclude: [EuiThemeProvider] } }
);
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,44 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { isNumber } from 'lodash';
import { ServiceNodeMetrics } from '../../../../../common/service_map';
import { ServiceNodeStats } from '../../../../../common/service_map';
import { ServiceStatsList } from './ServiceStatsList';
import { useFetcher, FETCH_STATUS } from '../../../../hooks/useFetcher';
import { useUrlParams } from '../../../../hooks/useUrlParams';
import { ServiceMetricList } from './ServiceMetricList';
import { AnomalyDetection } from './AnomalyDetection';
import { ServiceAnomalyStats } from '../../../../../common/anomaly_detection';

interface ServiceMetricFetcherProps {
interface ServiceStatsFetcherProps {
environment?: string;
smith marked this conversation as resolved.
Show resolved Hide resolved
serviceName: string;
serviceAnomalyStats: ServiceAnomalyStats | undefined;
}

export function ServiceMetricFetcher({
export function ServiceStatsFetcher({
serviceName,
serviceAnomalyStats,
}: ServiceMetricFetcherProps) {
}: ServiceStatsFetcherProps) {
const {
urlParams: { start, end, environment },
urlParams: { start, end },
uiFilters,
} = useUrlParams();

const {
data = { transactionStats: {} } as ServiceNodeMetrics,
data = { transactionStats: {} } as ServiceNodeStats,
status,
} = useFetcher(
(callApmApi) => {
if (serviceName && start && end) {
return callApmApi({
pathname: '/api/apm/service-map/service/{serviceName}',
params: { path: { serviceName }, query: { start, end, environment } },
params: {
path: { serviceName },
query: { start, end, uiFilters: JSON.stringify(uiFilters) },
},
});
}
},
[serviceName, start, end, environment],
[serviceName, start, end, uiFilters],
{
preservePreviousData: false,
}
Expand All @@ -60,20 +65,20 @@ export function ServiceMetricFetcher({

const {
avgCpuUsage,
avgErrorsPerMinute,
avgErrorRate,
avgMemoryUsage,
transactionStats: { avgRequestsPerMinute, avgTransactionDuration },
} = data;

const hasServiceData = [
avgCpuUsage,
avgErrorsPerMinute,
avgErrorRate,
avgMemoryUsage,
avgRequestsPerMinute,
avgTransactionDuration,
].some((stat) => isNumber(stat));

if (environment && !hasServiceData) {
if (!hasServiceData) {
return (
<EuiText color="subdued">
{i18n.translate('xpack.apm.serviceMap.popoverMetrics.noDataText', {
Expand All @@ -93,7 +98,7 @@ export function ServiceMetricFetcher({
<EuiHorizontalRule margin="xs" />
</>
)}
<ServiceMetricList {...data} />
<ServiceStatsList {...data} />
</>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n';
import { isNumber } from 'lodash';
import React from 'react';
import styled from 'styled-components';
import { ServiceNodeMetrics } from '../../../../../common/service_map';
import { ServiceNodeStats } from '../../../../../common/service_map';
import { asDuration, asPercent, tpmUnit } from '../../../../utils/formatters';

export const ItemRow = styled('tr')`
Expand All @@ -24,18 +24,18 @@ export const ItemDescription = styled('td')`
text-align: right;
`;

type ServiceMetricListProps = ServiceNodeMetrics;
type ServiceStatsListProps = ServiceNodeStats;

export function ServiceMetricList({
avgErrorsPerMinute,
export function ServiceStatsList({
transactionStats,
avgErrorRate,
avgCpuUsage,
avgMemoryUsage,
transactionStats,
}: ServiceMetricListProps) {
}: ServiceStatsListProps) {
const listItems = [
{
title: i18n.translate(
'xpack.apm.serviceMap.avgTransDurationPopoverMetric',
'xpack.apm.serviceMap.avgTransDurationPopoverStat',
{
defaultMessage: 'Trans. duration (avg.)',
}
Expand All @@ -58,27 +58,21 @@ export function ServiceMetricList({
: null,
},
{
title: i18n.translate(
'xpack.apm.serviceMap.avgErrorsPerMinutePopoverMetric',
{
defaultMessage: 'Errors per minute (avg.)',
}
),
description: avgErrorsPerMinute?.toFixed(2),
title: i18n.translate('xpack.apm.serviceMap.errorRatePopoverStat', {
defaultMessage: 'Error rate (avg.)',
}),
description: isNumber(avgErrorRate) ? asPercent(avgErrorRate, 1) : null,
},
{
title: i18n.translate('xpack.apm.serviceMap.avgCpuUsagePopoverMetric', {
title: i18n.translate('xpack.apm.serviceMap.avgCpuUsagePopoverStat', {
defaultMessage: 'CPU usage (avg.)',
}),
description: isNumber(avgCpuUsage) ? asPercent(avgCpuUsage, 1) : null,
},
{
title: i18n.translate(
'xpack.apm.serviceMap.avgMemoryUsagePopoverMetric',
{
defaultMessage: 'Memory usage (avg.)',
}
),
title: i18n.translate('xpack.apm.serviceMap.avgMemoryUsagePopoverStat', {
defaultMessage: 'Memory usage (avg.)',
}),
description: isNumber(avgMemoryUsage)
? asPercent(avgMemoryUsage, 1)
: null,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { Logger } from 'src/core/server';
import { UIFilters } from '../../../../typings/ui_filters';

export function getParsedUiFilters({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps this should be used here as well:

const uiFilters = JSON.parse(uiFiltersEncoded);

uiFilters,
logger,
}: {
uiFilters: string;
logger: Logger;
}): UIFilters {
try {
return JSON.parse(uiFilters);
} catch (error) {
logger.error(error);
}
return {};
}
Loading