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] Service inventory redesign #76744

Merged
merged 30 commits into from
Sep 14, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c7d8b6a
[APM] Service inventory redesign
dgieselaar Sep 3, 2020
d721c17
Split out HealthBadge/ServiceListMetric into separate files
dgieselaar Sep 4, 2020
edae816
Return empty object in anomaly alert
dgieselaar Sep 4, 2020
eed20ef
Remove unused translations
dgieselaar Sep 4, 2020
d78fd69
Merge branch 'master' of github.com:elastic/kibana into service-inven…
dgieselaar Sep 7, 2020
8a7fa9f
Review feedback
dgieselaar Sep 7, 2020
c1195c4
Merge branch 'master' of github.com:elastic/kibana into service-inven…
dgieselaar Sep 7, 2020
d2dce16
Use transaction error rate for services overview
dgieselaar Sep 7, 2020
a24fac2
Merge branch 'master' of github.com:elastic/kibana into service-inven…
dgieselaar Sep 7, 2020
1200f31
Merge branch 'master' of github.com:elastic/kibana into service-inven…
dgieselaar Sep 8, 2020
f35ca04
Remove unused translations
dgieselaar Sep 8, 2020
232d8e4
Merge branch 'master' of github.com:elastic/kibana into service-inven…
dgieselaar Sep 8, 2020
202e918
Merge branch 'master' of github.com:elastic/kibana into service-inven…
dgieselaar Sep 9, 2020
f008317
Merge branch 'master' of github.com:elastic/kibana into service-inven…
dgieselaar Sep 9, 2020
dd10641
API tests
dgieselaar Sep 9, 2020
a917452
Use empty icon/label for error rate
dgieselaar Sep 9, 2020
175f3a9
Merge branch 'master' of github.com:elastic/kibana into service-inven…
dgieselaar Sep 9, 2020
815559e
Fix top_services basic test
dgieselaar Sep 9, 2020
8a9011f
Merge branch 'master' of github.com:elastic/kibana into service-inven…
dgieselaar Sep 10, 2020
4c699bc
Clarify tests
dgieselaar Sep 10, 2020
033523e
Merge branch 'master' of github.com:elastic/kibana into service-inven…
dgieselaar Sep 10, 2020
3027310
Use archiveName variable
dgieselaar Sep 10, 2020
137d0b1
Rename isValidPlatinumLicense to isActivePlatinumLicense
dgieselaar Sep 10, 2020
1f46dda
Review feedback
dgieselaar Sep 10, 2020
46a2171
Review feedback
dgieselaar Sep 10, 2020
48ae3dd
Remove invalid stored item in useLocalStorage
dgieselaar Sep 10, 2020
a31722e
Merge branch 'master' into service-inventory
elasticmachine Sep 12, 2020
13f5ec5
Remove io-ts, add value tests
dgieselaar Sep 13, 2020
ca5316c
Merge branch 'master' of github.com:elastic/kibana into service-inven…
dgieselaar Sep 14, 2020
625ada6
Merge branch 'master' of github.com:elastic/kibana into service-inven…
dgieselaar Sep 14, 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
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { getSeverity, severity } from './getSeverity';
import { getSeverity, Severity } from './anomaly_detection';

describe('getSeverity', () => {
describe('when score is undefined', () => {
Expand All @@ -15,25 +15,25 @@ describe('getSeverity', () => {

describe('when score < 25', () => {
it('returns warning', () => {
expect(getSeverity(10)).toEqual(severity.warning);
expect(getSeverity(10)).toEqual(Severity.warning);
});
});

describe('when score is between 25 and 50', () => {
it('returns minor', () => {
expect(getSeverity(40)).toEqual(severity.minor);
expect(getSeverity(40)).toEqual(Severity.minor);
});
});

describe('when score is between 50 and 75', () => {
it('returns major', () => {
expect(getSeverity(60)).toEqual(severity.major);
expect(getSeverity(60)).toEqual(Severity.major);
});
});

describe('when score is 75 or more', () => {
it('returns critical', () => {
expect(getSeverity(100)).toEqual(severity.critical);
expect(getSeverity(100)).toEqual(Severity.critical);
});
});
});
40 changes: 40 additions & 0 deletions x-pack/plugins/apm/common/anomaly_detection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

import { i18n } from '@kbn/i18n';
import { EuiTheme } from '../../../legacy/common/eui_styled_components';

export interface ServiceAnomalyStats {
transactionType?: string;
Expand All @@ -13,6 +14,45 @@ export interface ServiceAnomalyStats {
jobId?: string;
}

export enum Severity {
critical = 'critical',
major = 'major',
minor = 'minor',
warning = 'warning',
}

// TODO: Replace with `getSeverity` from:
// https://github.com/elastic/kibana/blob/0f964f66916480f2de1f4b633e5afafc08cf62a0/x-pack/plugins/ml/common/util/anomaly_utils.ts#L129
export function getSeverity(score?: number) {
if (typeof score !== 'number') {
return undefined;
} else if (score < 25) {
return Severity.warning;
} else if (score >= 25 && score < 50) {
return Severity.minor;
} else if (score >= 50 && score < 75) {
return Severity.major;
} else if (score >= 75) {
return Severity.critical;
} else {
return undefined;
}
}

export function getSeverityColor(theme: EuiTheme, severity?: Severity) {
switch (severity) {
case Severity.warning:
return theme.eui.euiColorVis0;
case Severity.minor:
case Severity.major:
return theme.eui.euiColorVis5;
case Severity.critical:
return theme.eui.euiColorVis9;
default:
return;
}
}

export const ML_ERRORS = {
INVALID_LICENSE: i18n.translate(
'xpack.apm.anomaly_detection.error.invalid_license',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ import { useTheme } from '../../../../hooks/useTheme';
import { fontSize, px } from '../../../../style/variables';
import { asInteger, asDuration } from '../../../../utils/formatters';
import { MLJobLink } from '../../../shared/Links/MachineLearningLinks/MLJobLink';
import { getSeverityColor, popoverWidth } from '../cytoscapeOptions';
import { popoverWidth } from '../cytoscapeOptions';
import { TRANSACTION_REQUEST } from '../../../../../common/transaction_types';
import { ServiceAnomalyStats } from '../../../../../common/anomaly_detection';
import { getSeverity } from './getSeverity';
import {
getSeverity,
getSeverityColor,
ServiceAnomalyStats,
} from '../../../../../common/anomaly_detection';

const HealthStatusTitle = styled(EuiTitle)`
display: inline;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,15 @@ import {
} from '../../../../common/elasticsearch_fieldnames';
import { EuiTheme } from '../../../../../observability/public';
import { defaultIcon, iconForNode } from './icons';
import { ServiceAnomalyStats } from '../../../../common/anomaly_detection';
import { severity, getSeverity } from './Popover/getSeverity';
import {
getSeverity,
getSeverityColor,
ServiceAnomalyStats,
Severity,
} from '../../../../common/anomaly_detection';

export const popoverWidth = 280;

export function getSeverityColor(theme: EuiTheme, nodeSeverity?: string) {
switch (nodeSeverity) {
case severity.warning:
return theme.eui.euiColorVis0;
case severity.minor:
case severity.major:
return theme.eui.euiColorVis5;
case severity.critical:
return theme.eui.euiColorVis9;
default:
return;
}
}

function getNodeSeverity(el: cytoscape.NodeSingular) {
const serviceAnomalyStats: ServiceAnomalyStats | undefined = el.data(
'serviceAnomalyStats'
Expand Down Expand Up @@ -60,7 +50,7 @@ const getBorderStyle: cytoscape.Css.MapperFunction<
cytoscape.Css.LineStyle
> = (el: cytoscape.NodeSingular) => {
const nodeSeverity = getNodeSeverity(el);
if (nodeSeverity === severity.critical) {
if (nodeSeverity === Severity.critical) {
return 'double';
} else {
return 'solid';
Expand All @@ -70,9 +60,9 @@ const getBorderStyle: cytoscape.Css.MapperFunction<
function getBorderWidth(el: cytoscape.NodeSingular) {
const nodeSeverity = getNodeSeverity(el);

if (nodeSeverity === severity.minor || nodeSeverity === severity.major) {
if (nodeSeverity === Severity.minor || nodeSeverity === Severity.major) {
return 4;
} else if (nodeSeverity === severity.critical) {
} else if (nodeSeverity === Severity.critical) {
return 8;
} else {
return 4;
Expand Down
29 changes: 2 additions & 27 deletions x-pack/plugins/apm/public/components/app/ServiceMap/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,29 @@
*/

import cytoscape from 'cytoscape';
import { getNormalizedAgentName } from '../../../../common/agent_name';
import {
AGENT_NAME,
SPAN_SUBTYPE,
SPAN_TYPE,
} from '../../../../common/elasticsearch_fieldnames';
import awsIcon from './icons/aws.svg';
import cassandraIcon from './icons/cassandra.svg';
import darkIcon from './icons/dark.svg';
import databaseIcon from './icons/database.svg';
import defaultIconImport from './icons/default.svg';
import documentsIcon from './icons/documents.svg';
import dotNetIcon from './icons/dot-net.svg';
import elasticsearchIcon from './icons/elasticsearch.svg';
import globeIcon from './icons/globe.svg';
import goIcon from './icons/go.svg';
import graphqlIcon from './icons/graphql.svg';
import grpcIcon from './icons/grpc.svg';
import handlebarsIcon from './icons/handlebars.svg';
import javaIcon from './icons/java.svg';
import kafkaIcon from './icons/kafka.svg';
import mongodbIcon from './icons/mongodb.svg';
import mysqlIcon from './icons/mysql.svg';
import nodeJsIcon from './icons/nodejs.svg';
import phpIcon from './icons/php.svg';
import postgresqlIcon from './icons/postgresql.svg';
import pythonIcon from './icons/python.svg';
import redisIcon from './icons/redis.svg';
import rubyIcon from './icons/ruby.svg';
import rumJsIcon from './icons/rumjs.svg';
import websocketIcon from './icons/websocket.svg';
import javaIcon from '../../shared/AgentIcon/icons/java.svg';
import { getAgentIcon } from '../../shared/AgentIcon/get_agent_icon';

export const defaultIcon = defaultIconImport;

Expand Down Expand Up @@ -74,23 +66,6 @@ const typeIcons: { [key: string]: { [key: string]: string } } = {
},
};

const agentIcons: { [key: string]: string } = {
dark: darkIcon,
dotnet: dotNetIcon,
go: goIcon,
java: javaIcon,
'js-base': rumJsIcon,
nodejs: nodeJsIcon,
php: phpIcon,
python: pythonIcon,
ruby: rubyIcon,
};

function getAgentIcon(agentName?: string) {
const normalizedAgentName = getNormalizedAgentName(agentName);
return normalizedAgentName && agentIcons[normalizedAgentName];
}

function getSpanIcon(type?: string, subtype?: string) {
if (!type) {
return;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* 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 React from 'react';
import { EuiBadge } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import {
getSeverityColor,
Severity,
} from '../../../../../common/anomaly_detection';
import { useTheme } from '../../../../hooks/useTheme';

export function HealthBadge({ severity }: { severity?: Severity }) {
const theme = useTheme();

let label: string = '';

switch (severity) {
sorenlouv marked this conversation as resolved.
Show resolved Hide resolved
case Severity.critical:
label = i18n.translate(
'xpack.apm.servicesTable.serviceHealthStatus.critical',
{
defaultMessage: 'Critical',
}
);
break;

case Severity.major:
case Severity.minor:
label = i18n.translate(
'xpack.apm.servicesTable.serviceHealthStatus.warning',
{
defaultMessage: 'Warning',
}
);
break;

case Severity.warning:
label = i18n.translate(
'xpack.apm.servicesTable.serviceHealthStatus.healthy',
{
defaultMessage: 'Healthy',
}
);
break;

default:
label = i18n.translate(
'xpack.apm.servicesTable.serviceHealthStatus.unknown',
{
defaultMessage: 'Unknown',
}
);
break;
}

const unknownColor = theme.eui.euiColorLightShade;

return (
<EuiBadge color={getSeverityColor(theme, severity) ?? unknownColor}>
{label}
</EuiBadge>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* 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 React from 'react';
import { EuiCallOut } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { EuiButton } from '@elastic/eui';
import { EuiFlexItem } from '@elastic/eui';
import { EuiFlexGrid } from '@elastic/eui';
import { APMLink } from '../../../shared/Links/apm/APMLink';

export function MLCallout({ onDismiss }: { onDismiss: () => void }) {
return (
<EuiCallOut
title={i18n.translate('xpack.apm.serviceOverview.mlNudgeMessage.title', {
defaultMessage:
'Enable anomaly detection to see the health of your services',
})}
iconType="iInCircle"
>
<p>
{i18n.translate('xpack.apm.serviceOverview.mlNudgeMessage.content', {
defaultMessage: `Our integration with ML anomaly detection will enable you to see your services' health status`,
})}
</p>
<EuiFlexGrid gutterSize="s">
<EuiFlexItem grow={false}>
<EuiButton>
<APMLink
path="/settings/anomaly-detection"
style={{ whiteSpace: 'nowrap' }}
>
{i18n.translate(
'xpack.apm.serviceOverview.mlNudgeMessage.learnMoreButton',
{
defaultMessage: `Learn more`,
}
)}
</APMLink>
</EuiButton>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton onClick={() => onDismiss()}>
{i18n.translate(
'xpack.apm.serviceOverview.mlNudgeMessage.dismissButton',
{
defaultMessage: `Dismiss message`,
}
)}
</EuiButton>
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we convert this to EuiButtonEmpty because it's a secondary action compared to the "Learn more".

Copy link
Member Author

Choose a reason for hiding this comment

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

image

</EuiFlexItem>
</EuiFlexGrid>
</EuiCallOut>
);
}
Loading