[7.x] [APM] Experimental Service Map front end (#46497) (#47840)

Add service map tabs on the main APM screen and for individual services.

This is not yet hooked up to work with back-end data, so it always shows the same hard-coded graph.

This is experimental, so you must have x-pack.apm.serviceMapEnabled: true in your Kibana config for it to show up.

Also add "PSF" to the list of allowed licenses since a new dependency added uses this license (it's on the [green list](https://github.com/elastic/open-source/blob/master/elastic-product-policy.md#green-list).)

Fixes #44890
Fixes #44853
This commit is contained in:
Nathan L Smith 2019-10-10 13:02:54 -05:00 committed by GitHub
parent 67ce81bf53
commit 6b57c79f11
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 2190 additions and 425 deletions

File diff suppressed because it is too large Load diff

952
renovate.json5 Normal file
View file

@ -0,0 +1,952 @@
/**
* PLEASE DO NOT MODIFY
*
* This file is automatically generated by running `node scripts/build_renovate_config`
*
*/
{
extends: [
'config:base',
],
includePaths: [
'package.json',
'x-pack/package.json',
'x-pack/legacy/plugins/*/package.json',
'packages/*/package.json',
'test/plugin_functional/plugins/*/package.json',
'test/interpreter_functional/plugins/*/package.json',
],
baseBranches: [
'master',
],
labels: [
'release_note:skip',
'renovate',
'v8.0.0',
'v7.5.0',
],
major: {
labels: [
'release_note:skip',
'renovate',
'v8.0.0',
'v7.5.0',
'renovate:major',
],
},
masterIssue: true,
masterIssueApproval: true,
rangeStrategy: 'bump',
npm: {
lockFileMaintenance: {
enabled: false,
},
packageRules: [
{
groupSlug: 'eslint',
groupName: 'eslint related packages',
packagePatterns: [
'(\\b|_)eslint(\\b|_)',
],
},
{
groupSlug: 'babel',
groupName: 'babel related packages',
packagePatterns: [
'(\\b|_)babel(\\b|_)',
],
packageNames: [
'core-js',
'@types/core-js',
],
},
{
groupSlug: 'jest',
groupName: 'jest related packages',
packagePatterns: [
'(\\b|_)jest(\\b|_)',
],
},
{
groupSlug: '@elastic/charts',
groupName: '@elastic/charts related packages',
packageNames: [
'@elastic/charts',
'@types/elastic__charts',
],
reviewers: [
'markov00',
],
},
{
groupSlug: 'mocha',
groupName: 'mocha related packages',
packagePatterns: [
'(\\b|_)mocha(\\b|_)',
],
},
{
groupSlug: 'karma',
groupName: 'karma related packages',
packagePatterns: [
'(\\b|_)karma(\\b|_)',
],
},
{
groupSlug: 'gulp',
groupName: 'gulp related packages',
packagePatterns: [
'(\\b|_)gulp(\\b|_)',
],
},
{
groupSlug: 'grunt',
groupName: 'grunt related packages',
packagePatterns: [
'(\\b|_)grunt(\\b|_)',
],
},
{
groupSlug: 'angular',
groupName: 'angular related packages',
packagePatterns: [
'(\\b|_)angular(\\b|_)',
],
},
{
groupSlug: 'd3',
groupName: 'd3 related packages',
packagePatterns: [
'(\\b|_)d3(\\b|_)',
],
},
{
groupSlug: 'react',
groupName: 'react related packages',
packagePatterns: [
'(\\b|_)react(\\b|_)',
'(\\b|_)redux(\\b|_)',
'(\\b|_)enzyme(\\b|_)',
],
packageNames: [
'ngreact',
'@types/ngreact',
'recompose',
'@types/recompose',
'prop-types',
'@types/prop-types',
'typescript-fsa-reducers',
'@types/typescript-fsa-reducers',
'reselect',
'@types/reselect',
],
},
{
groupSlug: 'moment',
groupName: 'moment related packages',
packagePatterns: [
'(\\b|_)moment(\\b|_)',
],
},
{
groupSlug: 'graphql',
groupName: 'graphql related packages',
packagePatterns: [
'(\\b|_)graphql(\\b|_)',
'(\\b|_)apollo(\\b|_)',
],
},
{
groupSlug: 'webpack',
groupName: 'webpack related packages',
packagePatterns: [
'(\\b|_)webpack(\\b|_)',
'(\\b|_)loader(\\b|_)',
'(\\b|_)acorn(\\b|_)',
'(\\b|_)terser(\\b|_)',
],
packageNames: [
'mini-css-extract-plugin',
'@types/mini-css-extract-plugin',
'chokidar',
'@types/chokidar',
],
},
{
groupSlug: 'vega',
groupName: 'vega related packages',
packagePatterns: [
'(\\b|_)vega(\\b|_)',
],
enabled: false,
},
{
groupSlug: 'language server',
groupName: 'language server related packages',
packageNames: [
'vscode-jsonrpc',
'@types/vscode-jsonrpc',
'vscode-languageserver',
'@types/vscode-languageserver',
'vscode-languageserver-types',
'@types/vscode-languageserver-types',
],
},
{
groupSlug: 'hapi',
groupName: 'hapi related packages',
packagePatterns: [
'(\\b|_)hapi(\\b|_)',
],
packageNames: [
'hapi',
'@types/hapi',
'joi',
'@types/joi',
'boom',
'@types/boom',
'hoek',
'@types/hoek',
'h2o2',
'@types/h2o2',
'@elastic/good',
'@types/elastic__good',
'good-squeeze',
'@types/good-squeeze',
'inert',
'@types/inert',
],
},
{
groupSlug: 'dragselect',
groupName: 'dragselect related packages',
packageNames: [
'dragselect',
'@types/dragselect',
],
labels: [
'release_note:skip',
'renovate',
'v8.0.0',
'v7.5.0',
':ml',
],
},
{
groupSlug: 'api-documenter',
groupName: 'api-documenter related packages',
packageNames: [
'@microsoft/api-documenter',
'@types/microsoft__api-documenter',
'@microsoft/api-extractor',
'@types/microsoft__api-extractor',
],
enabled: false,
},
{
groupSlug: 'jsts',
groupName: 'jsts related packages',
packageNames: [
'jsts',
'@types/jsts',
],
allowedVersions: '^1.6.2',
},
{
groupSlug: 'storybook',
groupName: 'storybook related packages',
packagePatterns: [
'(\\b|_)storybook(\\b|_)',
],
},
{
groupSlug: 'typescript',
groupName: 'typescript related packages',
packagePatterns: [
'(\\b|_)ts(\\b|_)',
'(\\b|_)typescript(\\b|_)',
],
packageNames: [
'tslib',
'@types/tslib',
],
},
{
groupSlug: 'json-stable-stringify',
groupName: 'json-stable-stringify related packages',
packageNames: [
'json-stable-stringify',
'@types/json-stable-stringify',
],
},
{
groupSlug: 'lodash.clonedeep',
groupName: 'lodash.clonedeep related packages',
packageNames: [
'lodash.clonedeep',
'@types/lodash.clonedeep',
],
},
{
groupSlug: 'bluebird',
groupName: 'bluebird related packages',
packageNames: [
'bluebird',
'@types/bluebird',
],
},
{
groupSlug: 'chance',
groupName: 'chance related packages',
packageNames: [
'chance',
'@types/chance',
],
},
{
groupSlug: 'cheerio',
groupName: 'cheerio related packages',
packageNames: [
'cheerio',
'@types/cheerio',
],
},
{
groupSlug: 'chromedriver',
groupName: 'chromedriver related packages',
packageNames: [
'chromedriver',
'@types/chromedriver',
],
},
{
groupSlug: 'classnames',
groupName: 'classnames related packages',
packageNames: [
'classnames',
'@types/classnames',
],
},
{
groupSlug: 'dedent',
groupName: 'dedent related packages',
packageNames: [
'dedent',
'@types/dedent',
],
},
{
groupSlug: 'delete-empty',
groupName: 'delete-empty related packages',
packageNames: [
'delete-empty',
'@types/delete-empty',
],
},
{
groupSlug: 'elasticsearch',
groupName: 'elasticsearch related packages',
packageNames: [
'elasticsearch',
'@types/elasticsearch',
],
},
{
groupSlug: 'execa',
groupName: 'execa related packages',
packageNames: [
'execa',
'@types/execa',
],
},
{
groupSlug: 'fetch-mock',
groupName: 'fetch-mock related packages',
packageNames: [
'fetch-mock',
'@types/fetch-mock',
],
},
{
groupSlug: 'getopts',
groupName: 'getopts related packages',
packageNames: [
'getopts',
'@types/getopts',
],
},
{
groupSlug: 'glob',
groupName: 'glob related packages',
packageNames: [
'glob',
'@types/glob',
],
},
{
groupSlug: 'globby',
groupName: 'globby related packages',
packageNames: [
'globby',
'@types/globby',
],
},
{
groupSlug: 'has-ansi',
groupName: 'has-ansi related packages',
packageNames: [
'has-ansi',
'@types/has-ansi',
],
},
{
groupSlug: 'history',
groupName: 'history related packages',
packageNames: [
'history',
'@types/history',
],
},
{
groupSlug: 'humps',
groupName: 'humps related packages',
packageNames: [
'humps',
'@types/humps',
],
},
{
groupSlug: 'jquery',
groupName: 'jquery related packages',
packageNames: [
'jquery',
'@types/jquery',
],
},
{
groupSlug: 'js-yaml',
groupName: 'js-yaml related packages',
packageNames: [
'js-yaml',
'@types/js-yaml',
],
},
{
groupSlug: 'json5',
groupName: 'json5 related packages',
packageNames: [
'json5',
'@types/json5',
],
},
{
groupSlug: 'license-checker',
groupName: 'license-checker related packages',
packageNames: [
'license-checker',
'@types/license-checker',
],
},
{
groupSlug: 'listr',
groupName: 'listr related packages',
packageNames: [
'listr',
'@types/listr',
],
},
{
groupSlug: 'lodash',
groupName: 'lodash related packages',
packageNames: [
'lodash',
'@types/lodash',
],
},
{
groupSlug: 'lru-cache',
groupName: 'lru-cache related packages',
packageNames: [
'lru-cache',
'@types/lru-cache',
],
},
{
groupSlug: 'markdown-it',
groupName: 'markdown-it related packages',
packageNames: [
'markdown-it',
'@types/markdown-it',
],
},
{
groupSlug: 'minimatch',
groupName: 'minimatch related packages',
packageNames: [
'minimatch',
'@types/minimatch',
],
},
{
groupSlug: 'mustache',
groupName: 'mustache related packages',
packageNames: [
'mustache',
'@types/mustache',
],
},
{
groupSlug: 'node',
groupName: 'node related packages',
packageNames: [
'node',
'@types/node',
],
},
{
groupSlug: 'opn',
groupName: 'opn related packages',
packageNames: [
'opn',
'@types/opn',
],
},
{
groupSlug: 'pngjs',
groupName: 'pngjs related packages',
packageNames: [
'pngjs',
'@types/pngjs',
],
},
{
groupSlug: 'podium',
groupName: 'podium related packages',
packageNames: [
'podium',
'@types/podium',
],
},
{
groupSlug: 'request',
groupName: 'request related packages',
packageNames: [
'request',
'@types/request',
],
},
{
groupSlug: 'rimraf',
groupName: 'rimraf related packages',
packageNames: [
'rimraf',
'@types/rimraf',
],
},
{
groupSlug: 'selenium-webdriver',
groupName: 'selenium-webdriver related packages',
packageNames: [
'selenium-webdriver',
'@types/selenium-webdriver',
],
},
{
groupSlug: 'semver',
groupName: 'semver related packages',
packageNames: [
'semver',
'@types/semver',
],
},
{
groupSlug: 'sinon',
groupName: 'sinon related packages',
packageNames: [
'sinon',
'@types/sinon',
],
},
{
groupSlug: 'strip-ansi',
groupName: 'strip-ansi related packages',
packageNames: [
'strip-ansi',
'@types/strip-ansi',
],
},
{
groupSlug: 'styled-components',
groupName: 'styled-components related packages',
packageNames: [
'styled-components',
'@types/styled-components',
],
},
{
groupSlug: 'supertest',
groupName: 'supertest related packages',
packageNames: [
'supertest',
'@types/supertest',
],
},
{
groupSlug: 'type-detect',
groupName: 'type-detect related packages',
packageNames: [
'type-detect',
'@types/type-detect',
],
},
{
groupSlug: 'uuid',
groupName: 'uuid related packages',
packageNames: [
'uuid',
'@types/uuid',
],
},
{
groupSlug: 'vinyl-fs',
groupName: 'vinyl-fs related packages',
packageNames: [
'vinyl-fs',
'@types/vinyl-fs',
],
},
{
groupSlug: 'zen-observable',
groupName: 'zen-observable related packages',
packageNames: [
'zen-observable',
'@types/zen-observable',
],
},
{
groupSlug: 'base64-js',
groupName: 'base64-js related packages',
packageNames: [
'base64-js',
'@types/base64-js',
],
},
{
groupSlug: 'chroma-js',
groupName: 'chroma-js related packages',
packageNames: [
'chroma-js',
'@types/chroma-js',
],
},
{
groupSlug: 'color',
groupName: 'color related packages',
packageNames: [
'color',
'@types/color',
],
},
{
groupSlug: 'cytoscape',
groupName: 'cytoscape related packages',
packageNames: [
'cytoscape',
'@types/cytoscape',
],
},
{
groupSlug: 'fancy-log',
groupName: 'fancy-log related packages',
packageNames: [
'fancy-log',
'@types/fancy-log',
],
},
{
groupSlug: 'file-saver',
groupName: 'file-saver related packages',
packageNames: [
'file-saver',
'@types/file-saver',
],
},
{
groupSlug: 'getos',
groupName: 'getos related packages',
packageNames: [
'getos',
'@types/getos',
],
},
{
groupSlug: 'git-url-parse',
groupName: 'git-url-parse related packages',
packageNames: [
'git-url-parse',
'@types/git-url-parse',
],
},
{
groupSlug: 'jsdom',
groupName: 'jsdom related packages',
packageNames: [
'jsdom',
'@types/jsdom',
],
},
{
groupSlug: 'jsonwebtoken',
groupName: 'jsonwebtoken related packages',
packageNames: [
'jsonwebtoken',
'@types/jsonwebtoken',
],
},
{
groupSlug: 'mapbox-gl',
groupName: 'mapbox-gl related packages',
packageNames: [
'mapbox-gl',
'@types/mapbox-gl',
],
},
{
groupSlug: 'memoize-one',
groupName: 'memoize-one related packages',
packageNames: [
'memoize-one',
'@types/memoize-one',
],
},
{
groupSlug: 'mime',
groupName: 'mime related packages',
packageNames: [
'mime',
'@types/mime',
],
},
{
groupSlug: 'nock',
groupName: 'nock related packages',
packageNames: [
'nock',
'@types/nock',
],
},
{
groupSlug: 'node-fetch',
groupName: 'node-fetch related packages',
packageNames: [
'node-fetch',
'@types/node-fetch',
],
},
{
groupSlug: 'nodemailer',
groupName: 'nodemailer related packages',
packageNames: [
'nodemailer',
'@types/nodemailer',
],
},
{
groupSlug: 'object-hash',
groupName: 'object-hash related packages',
packageNames: [
'object-hash',
'@types/object-hash',
],
},
{
groupSlug: 'papaparse',
groupName: 'papaparse related packages',
packageNames: [
'papaparse',
'@types/papaparse',
],
},
{
groupSlug: 'proper-lockfile',
groupName: 'proper-lockfile related packages',
packageNames: [
'proper-lockfile',
'@types/proper-lockfile',
],
},
{
groupSlug: 'puppeteer',
groupName: 'puppeteer related packages',
packageNames: [
'puppeteer',
'@types/puppeteer',
],
},
{
groupSlug: 'reduce-reducers',
groupName: 'reduce-reducers related packages',
packageNames: [
'reduce-reducers',
'@types/reduce-reducers',
],
},
{
groupSlug: 'tar-fs',
groupName: 'tar-fs related packages',
packageNames: [
'tar-fs',
'@types/tar-fs',
],
},
{
groupSlug: 'tinycolor2',
groupName: 'tinycolor2 related packages',
packageNames: [
'tinycolor2',
'@types/tinycolor2',
],
},
{
groupSlug: 'xml2js',
groupName: 'xml2js related packages',
packageNames: [
'xml2js',
'@types/xml2js',
],
},
{
groupSlug: 'xml-crypto',
groupName: 'xml-crypto related packages',
packageNames: [
'xml-crypto',
'@types/xml-crypto',
],
},
{
groupSlug: 'intl-relativeformat',
groupName: 'intl-relativeformat related packages',
packageNames: [
'intl-relativeformat',
'@types/intl-relativeformat',
],
},
{
groupSlug: 'cmd-shim',
groupName: 'cmd-shim related packages',
packageNames: [
'cmd-shim',
'@types/cmd-shim',
],
},
{
groupSlug: 'cpy',
groupName: 'cpy related packages',
packageNames: [
'cpy',
'@types/cpy',
],
},
{
groupSlug: 'indent-string',
groupName: 'indent-string related packages',
packageNames: [
'indent-string',
'@types/indent-string',
],
},
{
groupSlug: 'lodash.clonedeepwith',
groupName: 'lodash.clonedeepwith related packages',
packageNames: [
'lodash.clonedeepwith',
'@types/lodash.clonedeepwith',
],
},
{
groupSlug: 'log-symbols',
groupName: 'log-symbols related packages',
packageNames: [
'log-symbols',
'@types/log-symbols',
],
},
{
groupSlug: 'ncp',
groupName: 'ncp related packages',
packageNames: [
'ncp',
'@types/ncp',
],
},
{
groupSlug: 'ora',
groupName: 'ora related packages',
packageNames: [
'ora',
'@types/ora',
],
},
{
groupSlug: 'read-pkg',
groupName: 'read-pkg related packages',
packageNames: [
'read-pkg',
'@types/read-pkg',
],
},
{
groupSlug: 'strong-log-transformer',
groupName: 'strong-log-transformer related packages',
packageNames: [
'strong-log-transformer',
'@types/strong-log-transformer',
],
},
{
groupSlug: 'tempy',
groupName: 'tempy related packages',
packageNames: [
'tempy',
'@types/tempy',
],
},
{
groupSlug: 'wrap-ansi',
groupName: 'wrap-ansi related packages',
packageNames: [
'wrap-ansi',
'@types/wrap-ansi',
],
},
{
groupSlug: 'write-pkg',
groupName: 'write-pkg related packages',
packageNames: [
'write-pkg',
'@types/write-pkg',
],
},
{
groupSlug: 'parse-link-header',
groupName: 'parse-link-header related packages',
packageNames: [
'parse-link-header',
'@types/parse-link-header',
],
},
{
packagePatterns: [
'^@kbn/.*',
],
enabled: false,
},
],
},
prConcurrentLimit: 0,
vulnerabilityAlerts: {
enabled: false,
},
rebaseStalePrs: false,
semanticCommits: false,
}

View file

@ -63,6 +63,7 @@ export const LICENSE_WHITELIST = [
'MIT/X11',
'new BSD, and MIT',
'(OFL-1.1 AND MIT)',
'PSF',
'Public Domain',
'Unlicense',
'WTFPL OR ISC',

View file

@ -43,6 +43,7 @@ export const apm: LegacyPluginInitializer = kibana => {
apmUiEnabled: config.get('xpack.apm.ui.enabled'),
// TODO: rename to apm_oss.indexPatternTitle in 7.0 (breaking change)
apmIndexPatternTitle: config.get('apm_oss.indexPattern'),
apmServiceMapEnabled: config.get('xpack.apm.serviceMapEnabled'),
apmTransactionIndices: config.get('apm_oss.transactionIndices')
};
},
@ -70,7 +71,10 @@ export const apm: LegacyPluginInitializer = kibana => {
// buckets
minimumBucketSize: Joi.number().default(15),
bucketTargetCount: Joi.number().default(15)
bucketTargetCount: Joi.number().default(15),
// service map
serviceMapEnabled: Joi.boolean().default(false)
}).default();
},

View file

@ -13,6 +13,7 @@ import {
EuiSpacer
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { npStart } from 'ui/new_platform';
import React from 'react';
import { $ElementType } from 'utility-types';
import { ApmHeader } from '../../shared/ApmHeader';
@ -23,6 +24,8 @@ import { ServiceOverviewLink } from '../../shared/Links/apm/ServiceOverviewLink'
import { TraceOverviewLink } from '../../shared/Links/apm/TraceOverviewLink';
import { EuiTabLink } from '../../shared/EuiTabLink';
import { SettingsLink } from '../../shared/Links/apm/SettingsLink';
import { ServiceMapLink } from '../../shared/Links/apm/ServiceMapLink';
import { ServiceMap } from '../ServiceMap';
const homeTabs = [
{
@ -49,12 +52,26 @@ const homeTabs = [
}
];
if (npStart.core.injectedMetadata.getInjectedVar('apmServiceMapEnabled')) {
homeTabs.push({
link: (
<ServiceMapLink>
{i18n.translate('xpack.apm.home.serviceMapTabLabel', {
defaultMessage: 'Service Map'
})}
</ServiceMapLink>
),
render: () => <ServiceMap />,
name: 'service-map'
});
}
const SETTINGS_LINK_LABEL = i18n.translate('xpack.apm.settingsLinkLabel', {
defaultMessage: 'Settings'
});
interface Props {
tab: 'traces' | 'services';
tab: 'traces' | 'services' | 'service-map';
}
export function Home({ tab }: Props) {

View file

@ -7,6 +7,7 @@
import { i18n } from '@kbn/i18n';
import React from 'react';
import { Redirect, RouteComponentProps } from 'react-router-dom';
import { npStart } from 'ui/new_platform';
import { ErrorGroupDetails } from '../../ErrorGroupDetails';
import { ServiceDetails } from '../../ServiceDetails';
import { TransactionDetails } from '../../TransactionDetails';
@ -149,3 +150,26 @@ export const routes: BreadcrumbRoute[] = [
name: RouteName.TRANSACTION_NAME
}
];
if (npStart.core.injectedMetadata.getInjectedVar('apmServiceMapEnabled')) {
routes.push(
{
exact: true,
path: '/service-map',
component: () => <Home tab="service-map" />,
breadcrumb: i18n.translate('xpack.apm.breadcrumb.serviceMapTitle', {
defaultMessage: 'Service Map'
}),
name: RouteName.SERVICE_MAP
},
{
exact: true,
path: '/services/:serviceName/service-map',
component: () => <ServiceDetails tab="service-map" />,
breadcrumb: i18n.translate('xpack.apm.breadcrumb.serviceMapTitle', {
defaultMessage: 'Service Map'
}),
name: RouteName.SINGLE_SERVICE_MAP
}
);
}

View file

@ -7,6 +7,8 @@
export enum RouteName {
HOME = 'home',
SERVICES = 'services',
SERVICE_MAP = 'service-map',
SINGLE_SERVICE_MAP = 'single-service-map',
TRACES = 'traces',
SERVICE = 'service',
TRANSACTIONS = 'transactions',

View file

@ -7,6 +7,7 @@
import { i18n } from '@kbn/i18n';
import React from 'react';
import { EuiTabs, EuiSpacer } from '@elastic/eui';
import { npStart } from 'ui/new_platform';
import { ErrorGroupOverview } from '../ErrorGroupOverview';
import { TransactionOverview } from '../TransactionOverview';
import { ServiceMetrics } from '../ServiceMetrics';
@ -19,9 +20,11 @@ import { MetricOverviewLink } from '../../shared/Links/apm/MetricOverviewLink';
import { ServiceNodeOverviewLink } from '../../shared/Links/apm/ServiceNodeOverviewLink';
import { ServiceNodeOverview } from '../ServiceNodeOverview';
import { useAgentName } from '../../../hooks/useAgentName';
import { ServiceMap } from '../ServiceMap';
import { ServiceMapLink } from '../../shared/Links/apm/ServiceMapLink';
interface Props {
tab: 'transactions' | 'errors' | 'metrics' | 'nodes';
tab: 'transactions' | 'errors' | 'metrics' | 'nodes' | 'service-map';
}
export function ServiceDetailTabs({ tab }: Props) {
@ -90,6 +93,22 @@ export function ServiceDetailTabs({ tab }: Props) {
tabs.push(metricsTab);
}
const serviceMapTab = {
link: (
<ServiceMapLink serviceName={serviceName}>
{i18n.translate('xpack.apm.home.serviceMapTabLabel', {
defaultMessage: 'Service Map'
})}
</ServiceMapLink>
),
render: () => <ServiceMap serviceName={serviceName} />,
name: 'service-map'
};
if (npStart.core.injectedMetadata.getInjectedVar('apmServiceMapEnabled')) {
tabs.push(serviceMapTab);
}
const selectedTab = tabs.find(serviceTab => serviceTab.name === tab);
return (

View file

@ -0,0 +1,108 @@
/*
* 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, { useContext, useState, useEffect } from 'react';
import { EuiButtonIcon, EuiPanel } from '@elastic/eui';
import theme from '@elastic/eui/dist/eui_theme_light.json';
import styled from 'styled-components';
import { i18n } from '@kbn/i18n';
import { CytoscapeContext } from './Cytoscape';
import { FullscreenPanel } from './FullscreenPanel';
const Container = styled('div')`
left: ${theme.gutterTypes.gutterMedium};
position: absolute;
top: ${theme.gutterTypes.gutterSmall};
`;
const Button = styled(EuiButtonIcon)`
display: block;
margin: ${theme.paddingSizes.xs};
`;
const ZoomInButton = styled(Button)`
margin-bottom: ${theme.paddingSizes.s};
`;
const ZoomPanel = styled(EuiPanel)`
margin-bottom: ${theme.paddingSizes.s};
`;
const duration = parseInt(theme.euiAnimSpeedFast, 10);
const steps = 5;
function doZoom(cy: cytoscape.Core | undefined, increment: number) {
if (cy) {
const level = cy.zoom() + increment;
cy.animate({
duration,
zoom: { level, position: cy.$('.primary').position() }
});
}
}
export function Controls() {
const cy = useContext(CytoscapeContext);
const [zoom, setZoom] = useState((cy && cy.zoom()) || 1);
useEffect(() => {
if (cy) {
cy.on('zoom', event => {
setZoom(event.cy.zoom());
});
}
}, [cy]);
function zoomIn() {
doZoom(cy, increment);
}
function zoomOut() {
doZoom(cy, -increment);
}
if (!cy) {
return null;
}
const maxZoom = cy.maxZoom();
const isMaxZoom = zoom === maxZoom;
const minZoom = cy.minZoom();
const isMinZoom = zoom === minZoom;
const increment = (maxZoom - minZoom) / steps;
const mapDomElement = cy.container();
const zoomInLabel = i18n.translate('xpack.apm.serviceMap.zoomIn', {
defaultMessage: 'Zoom in'
});
const zoomOutLabel = i18n.translate('xpack.apm.serviceMap.zoomOut', {
defaultMessage: 'Zoom out'
});
return (
<Container>
<ZoomPanel hasShadow={true} paddingSize="none">
<ZoomInButton
aria-label={zoomInLabel}
color="text"
disabled={isMaxZoom}
iconType="plusInCircleFilled"
onClick={zoomIn}
title={zoomInLabel}
/>
<Button
aria-label={zoomOutLabel}
color="text"
disabled={isMinZoom}
iconType="minusInCircleFilled"
onClick={zoomOut}
title={zoomOutLabel}
/>
</ZoomPanel>
<FullscreenPanel element={mapDomElement} />
</Container>
);
}

View file

@ -0,0 +1,93 @@
/*
* 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, {
CSSProperties,
useState,
useRef,
useEffect,
ReactNode,
createContext
} from 'react';
import cytoscape from 'cytoscape';
import dagre from 'cytoscape-dagre';
import { cytoscapeOptions } from './cytoscapeOptions';
cytoscape.use(dagre);
export const CytoscapeContext = createContext<cytoscape.Core | undefined>(
undefined
);
interface CytoscapeProps {
children?: ReactNode;
elements: cytoscape.ElementDefinition[];
serviceName?: string;
style: CSSProperties;
}
function useCytoscape(options: cytoscape.CytoscapeOptions) {
const [cy, setCy] = useState<cytoscape.Core | undefined>(undefined);
const ref = useRef(null);
useEffect(() => {
if (!cy) {
setCy(cytoscape({ ...options, container: ref.current }));
}
}, [options, cy]);
// Destroy the cytoscape instance on unmount
useEffect(() => {
return () => {
if (cy) {
cy.destroy();
}
};
}, [cy]);
return [ref, cy] as [React.MutableRefObject<any>, cytoscape.Core | undefined];
}
export function Cytoscape({
children,
elements,
serviceName,
style
}: CytoscapeProps) {
const [ref, cy] = useCytoscape({ ...cytoscapeOptions, elements });
// Trigger a custom "data" event when data changes
useEffect(() => {
if (cy) {
cy.add(elements);
cy.trigger('data');
}
}, [cy, elements]);
// Set up cytoscape event handlers
useEffect(() => {
if (cy) {
cy.on('data', event => {
// Add the "primary" class to the node if its id matches the serviceName.
if (cy.nodes().length > 0 && serviceName) {
cy.getElementById(serviceName).addClass('primary');
}
if (event.cy.elements().length > 0) {
cy.layout(cytoscapeOptions.layout as cytoscape.LayoutOptions).run();
}
});
}
}, [cy, serviceName]);
return (
<CytoscapeContext.Provider value={cy}>
<div ref={ref} style={style}>
{children}
</div>
</CytoscapeContext.Provider>
);
}

View file

@ -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 { EuiButtonIcon, EuiPanel } from '@elastic/eui';
import styled from 'styled-components';
import theme from '@elastic/eui/dist/eui_theme_light.json';
import { i18n } from '@kbn/i18n';
const Button = styled(EuiButtonIcon)`
display: block;
margin: ${theme.paddingSizes.xs};
`;
interface FullscreenPanelProps {
element: Element | null;
}
export function FullscreenPanel({ element }: FullscreenPanelProps) {
const canDoFullscreen =
element && element.ownerDocument && element.ownerDocument.fullscreenEnabled;
if (!canDoFullscreen) {
return null;
}
function doFullscreen() {
if (element && element.ownerDocument && canDoFullscreen) {
const isFullscreen = element.ownerDocument.fullscreenElement !== null;
if (isFullscreen) {
element.ownerDocument.exitFullscreen();
} else {
element.requestFullscreen();
}
}
}
const label = i18n.translate('xpack.apm.serviceMap.fullscreen', {
defaultMessage: 'Full screen'
});
return (
<EuiPanel hasShadow={true} paddingSize="none">
<Button
aria-label={label}
color="text"
iconType="fullScreen"
onClick={doFullscreen}
title={label}
/>
</EuiPanel>
);
}

View file

@ -0,0 +1,92 @@
/*
* 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 cytoscape from 'cytoscape';
import theme from '@elastic/eui/dist/eui_theme_light.json';
import { icons, defaultIcon } from './icons';
const layout = {
animate: true,
animationEasing: theme.euiAnimSlightBounce as cytoscape.Css.TransitionTimingFunction,
animationDuration: parseInt(theme.euiAnimSpeedFast, 10),
name: 'dagre',
nodeDimensionsIncludeLabels: true,
rankDir: 'LR',
spacingFactor: 2
};
function isDatabaseOrExternal(agentName: string) {
return agentName === 'database' || agentName === 'external';
}
const style: cytoscape.Stylesheet[] = [
{
selector: 'node',
style: {
'background-color': 'white',
// The DefinitelyTyped definitions don't specify that a function can be
// used here.
//
// @ts-ignore
'background-image': (el: cytoscape.NodeSingular) =>
icons[el.data('agentName')] || defaultIcon,
'background-height': (el: cytoscape.NodeSingular) =>
isDatabaseOrExternal(el.data('agentName')) ? '40%' : '80%',
'background-width': (el: cytoscape.NodeSingular) =>
isDatabaseOrExternal(el.data('agentName')) ? '40%' : '80%',
'border-color': (el: cytoscape.NodeSingular) =>
el.hasClass('primary')
? theme.euiColorSecondary
: theme.euiColorMediumShade,
'border-width': 2,
color: theme.textColors.default,
// theme.euiFontFamily doesn't work here for some reason, so we're just
// specifying a subset of the fonts for the label text.
'font-family': 'Inter UI, Segoe UI, Helvetica, Arial, sans-serif',
'font-size': theme.euiFontSizeXS,
height: theme.avatarSizing.l.size,
label: 'data(id)',
'min-zoomed-font-size': theme.euiSizeL,
'overlay-opacity': 0,
shape: (el: cytoscape.NodeSingular) =>
isDatabaseOrExternal(el.data('agentName')) ? 'diamond' : 'ellipse',
'text-background-color': theme.euiColorLightestShade,
'text-background-opacity': 0,
'text-background-padding': theme.paddingSizes.xs,
'text-background-shape': 'roundrectangle',
'text-margin-y': theme.paddingSizes.s,
'text-max-width': '85px',
'text-valign': 'bottom',
'text-wrap': 'ellipsis',
width: theme.avatarSizing.l.size
}
},
{
selector: 'edge',
style: {
'curve-style': 'bezier',
'line-color': theme.euiColorMediumShade,
'overlay-opacity': 0,
'target-arrow-color': theme.euiColorMediumShade,
'target-arrow-shape': 'triangle',
// The DefinitelyTyped definitions don't specify this property since it's
// fairly new.
//
// @ts-ignore
'target-distance-from-node': theme.paddingSizes.xs,
width: 2
}
}
];
export const cytoscapeOptions: cytoscape.CytoscapeOptions = {
autoungrabify: true,
autounselectify: true,
boxSelectionEnabled: false,
layout,
maxZoom: 3,
minZoom: 0.2,
style
};

View file

@ -0,0 +1,39 @@
/*
* 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 theme from '@elastic/eui/dist/eui_theme_light.json';
import databaseIcon from './icons/database.svg';
import globeIcon from './icons/globe.svg';
function getAvatarIcon(
text = '',
backgroundColor = 'transparent',
foregroundColor = 'white'
) {
return (
'data:image/svg+xml;utf8,' +
encodeURIComponent(`<svg width="80" height="80" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<circle cx="40" cy="40" fill="${backgroundColor}" r="40" stroke-width="0" />
<text fill="${foregroundColor}" font-family="'Inter UI', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Helvetica', 'Arial', sans-serif" font-size="36" text-anchor="middle" x="40" xml:space="preserve" y="52">${text}</text>
</svg>
`)
);
}
// The colors here are taken from the logos of the corresponding technologies
export const icons: { [key: string]: string } = {
database: databaseIcon,
dotnet: getAvatarIcon('.N', '#8562AD'),
external: globeIcon,
go: getAvatarIcon('Go', '#00A9D6'),
java: getAvatarIcon('Jv', '#41717E'),
'js-base': getAvatarIcon('JS', '#F0DB4E', theme.euiTextColor),
nodejs: getAvatarIcon('No', '#689E62'),
python: getAvatarIcon('Py', '#376994'),
ruby: getAvatarIcon('Rb', '#CC362E')
};
export const defaultIcon = getAvatarIcon();

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path d="M2,12 L14,12 L14,10.030739 C12.7751029,10.611548 10.5463251,11 8,11 C5.45367486,11 3.22489715,10.611548 2,10.030739 L2,12 Z M1,12 L1,3 C1,1.8954305 4.13400675,1 8,1 C11.8659932,1 15,1.8954305 15,3 L15,12 C15,13.1045695 11.8659932,14 8,14 C4.13400675,14 1,13.1045695 1,12 Z M2,9 L14,9 L14,7.03073903 C12.7751029,7.61154795 10.5463251,8 8,8 C5.45367486,8 3.22489715,7.61154795 2,7.03073903 L2,9 Z M2,4.03073903 L2,6 L14,6 L14,4.03073903 C12.7751029,4.61154795 10.5463251,5 8,5 C5.45367486,5 3.22489715,4.61154795 2,4.03073903 Z M12.6750263,2.54731039 C11.4669244,2.2021384 9.7942434,2 8,2 C6.2057566,2 4.53307561,2.2021384 3.32497366,2.54731039 C2.83334959,2.6877744 2.44511574,2.84536607 2.18860384,3 C2.44511574,3.15463393 2.83334959,3.3122256 3.32497366,3.45268961 C4.53307561,3.7978616 6.2057566,4 8,4 C9.7942434,4 11.4669244,3.7978616 12.6750263,3.45268961 C13.1666504,3.3122256 13.5548843,3.15463393 13.8113962,3 C13.5548843,2.84536607 13.1666504,2.6877744 12.6750263,2.54731039 Z M2.00012207,6 C2.25663397,6.15463393 2.83334959,6.3122256 3.32497366,6.45268961 C4.53307561,6.7978616 6.2057566,7 8,7 C9.7942434,7 11.4669244,6.7978616 12.6750263,6.45268961 C13.1666504,6.3122256 13.7452581,6.15463393 14.00177,6 C14.00177,6 2.00012207,6 2.00012207,6 Z M2.00012207,9 C2.25663397,9.15463393 2.83334959,9.3122256 3.32497366,9.45268961 C4.53307561,9.7978616 6.2057566,10 8,10 C9.7942434,10 11.4669244,9.7978616 12.6750263,9.45268961 C13.1666504,9.3122256 13.7452581,9.15463393 14.00177,9 C14.00177,9 2.00012207,9 2.00012207,9 Z M2.00012207,12 C2.25663397,12.1546339 2.83334959,12.3122256 3.32497366,12.4526896 C4.53307561,12.7978616 6.2057566,13 8,13 C9.7942434,13 11.4669244,12.7978616 12.6750263,12.4526896 C13.1666504,12.3122256 13.7452581,12.1546339 14.00177,12 C14.00177,12 2.00012207,12 2.00012207,12 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path d="M1.01894482,8 C1.10254676,9.09899404 1.4594409,10.1215971 2.02181791,11 L4.40368841,11 C4.18019933,10.0940164 4.04077017,9.07812112 4.0076544,8 L1.01894482,8 Z M1.01894482,7 L4.0076544,7 C4.04077017,5.92187888 4.18019933,4.90598356 4.40368841,4 L2.02181791,4 C1.4594409,4.87840285 1.10254676,5.90100596 1.01894482,7 Z M13.9810552,8 L10.9923456,8 C10.9592298,9.07812112 10.8198007,10.0940164 10.5963116,11 L12.9781821,11 C13.5405591,10.1215971 13.8974532,9.09899404 13.9810552,8 Z M13.9810552,7 C13.8974532,5.90100596 13.5405591,4.87840285 12.9781821,4 L10.5963116,4 C10.8198007,4.90598356 10.9592298,5.92187888 10.9923456,7 L13.9810552,7 Z M5.00830927,8 C5.04518452,9.10676001 5.20260591,10.126832 5.4366712,11 L9.5633288,11 C9.79739409,10.126832 9.95481548,9.10676001 9.99169073,8 L5.00830927,8 Z M5.00830927,7 L9.99169073,7 C9.95481548,5.89323999 9.79739409,4.87316799 9.5633288,4 L5.4366712,4 C5.20260591,4.87316799 5.04518452,5.89323999 5.00830927,7 Z M0.0164022774,8 L0,8 L0,7 L0.0164022774,7 C0.27369532,3.09098409 3.52587865,0 7.5,0 C11.4741213,0 14.7263047,3.09098409 14.9835977,7 L15,7 L15,8 L14.9835977,8 C14.7263047,11.9090159 11.4741213,15 7.5,15 C3.52587865,15 0.27369532,11.9090159 0.0164022774,8 Z M2.80957219,12 C3.55098945,12.7725926 4.48144138,13.3623845 5.52657413,13.6950218 C5.20958281,13.2304541 4.9300672,12.657078 4.69974367,12 L2.80957219,12 Z M12.1904278,12 L10.3002563,12 C10.0699328,12.657078 9.79041719,13.2304541 9.47342587,13.6950218 C10.5185586,13.3623845 11.4490105,12.7725926 12.1904278,12 Z M5.76185069,12 C6.24600608,13.2396967 6.89365779,14 7.5,14 C8.10634221,14 8.75399392,13.2396967 9.23814931,12 L5.76185069,12 Z M2.80957219,3 L4.69974367,3 C4.9300672,2.34292204 5.20958281,1.76954592 5.52657413,1.30497818 C4.48144138,1.63761552 3.55098945,2.2274074 2.80957219,3 Z M12.1904278,3 C11.4490105,2.2274074 10.5185586,1.63761552 9.47342587,1.30497818 C9.79041719,1.76954592 10.0699328,2.34292204 10.3002563,3 L12.1904278,3 Z M5.76185069,3 L9.23814931,3 C8.75399392,1.76030334 8.10634221,1 7.5,1 C6.89365779,1 6.24600608,1.76030334 5.76185069,3 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -0,0 +1,64 @@
/*
* 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 theme from '@elastic/eui/dist/eui_theme_light.json';
import { useUrlParams } from '../../../hooks/useUrlParams';
import { useFetcher } from '../../../hooks/useFetcher';
import { callApmApi } from '../../../services/rest/callApmApi';
import { Cytoscape } from './Cytoscape';
import { Controls } from './Controls';
interface ServiceMapProps {
serviceName?: string;
}
const cytoscapeDivStyle = {
height: '85vh',
background: `linear-gradient(
90deg,
${theme.euiPageBackgroundColor}
calc(${theme.euiSizeL} - calc(${theme.euiSizeXS} / 2)),
transparent 1%
)
center,
linear-gradient(
${theme.euiPageBackgroundColor}
calc(${theme.euiSizeL} - calc(${theme.euiSizeXS} / 2)),
transparent 1%
)
center,
${theme.euiColorLightShade}`,
backgroundSize: `${theme.euiSizeL} ${theme.euiSizeL}`,
margin: `-${theme.gutterTypes.gutterLarge}`
};
export function ServiceMap({ serviceName }: ServiceMapProps) {
const {
urlParams: { start, end }
} = useUrlParams();
const { data } = useFetcher(async () => {
if (start && end) {
return callApmApi({
pathname: '/api/apm/service-map',
params: { query: { start, end } }
});
}
}, [start, end]);
const elements = Array.isArray(data) ? data : [];
return (
<Cytoscape
elements={elements}
serviceName={serviceName}
style={cytoscapeDivStyle}
>
<Controls />
</Cytoscape>
);
}

View file

@ -0,0 +1,26 @@
/*
* 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.
*/
/*
* 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 { APMLink, APMLinkExtendProps } from './APMLink';
interface ServiceMapLinkProps extends APMLinkExtendProps {
serviceName?: string;
}
const ServiceMapLink = ({ serviceName, ...rest }: ServiceMapLinkProps) => {
const path = serviceName
? `/services/${serviceName}/service-map`
: '/service-map';
return <APMLink path={path} {...rest} />;
};
export { ServiceMapLink };

View file

@ -94,7 +94,11 @@ export function getPathParams(pathname: string = '') {
return {
serviceName
};
case 'service-map':
return {
processorEvent: 'service-map',
serviceName
};
default:
return {
processorEvent: 'transaction'

View file

@ -0,0 +1,88 @@
/*
* 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 cytoscape from 'cytoscape';
import { PromiseReturnType } from '../../../typings/common';
// This response right now just returns experimental data.
export type ServiceMapResponse = PromiseReturnType<typeof getServiceMap>;
export async function getServiceMap(): Promise<cytoscape.ElementDefinition[]> {
return [
{ data: { id: 'client', agentName: 'js-base' } },
{ data: { id: 'opbeans-node', agentName: 'nodejs' } },
{ data: { id: 'opbeans-python', agentName: 'python' } },
{ data: { id: 'opbeans-java', agentName: 'java' } },
{ data: { id: 'opbeans-ruby', agentName: 'ruby' } },
{ data: { id: 'opbeans-go', agentName: 'go' } },
{ data: { id: 'opbeans-go-2', agentName: 'go' } },
{ data: { id: 'opbeans-dotnet', agentName: 'dotnet' } },
{ data: { id: 'database', agentName: 'database' } },
{ data: { id: 'external API', agentName: 'external' } },
{
data: {
id: 'opbeans-client~opbeans-node',
source: 'client',
target: 'opbeans-node'
}
},
{
data: {
id: 'opbeans-client~opbeans-python',
source: 'client',
target: 'opbeans-python'
}
},
{
data: {
id: 'opbeans-python~opbeans-go',
source: 'opbeans-python',
target: 'opbeans-go'
}
},
{
data: {
id: 'opbeans-python~opbeans-go-2',
source: 'opbeans-python',
target: 'opbeans-go-2'
}
},
{
data: {
id: 'opbeans-python~opbeans-dotnet',
source: 'opbeans-python',
target: 'opbeans-dotnet'
}
},
{
data: {
id: 'opbeans-node~opbeans-java',
source: 'opbeans-node',
target: 'opbeans-java'
}
},
{
data: {
id: 'opbeans-node~database',
source: 'opbeans-node',
target: 'database'
}
},
{
data: {
id: 'opbeans-go-2~opbeans-ruby',
source: 'opbeans-go-2',
target: 'opbeans-ruby'
}
},
{
data: {
id: 'opbeans-go-2~external API',
source: 'opbeans-go-2',
target: 'external API'
}
}
];
}

View file

@ -3,6 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { indexPatternRoute } from './index_pattern';
import {
errorDistributionRoute,
@ -46,6 +47,7 @@ import {
uiFiltersEnvironmentsRoute
} from './ui_filters';
import { createApi } from './create_api';
import { serviceMapRoute } from './services';
const createApmApi = () => {
const api = createApi()
@ -96,7 +98,8 @@ const createApmApi = () => {
.add(transactionGroupsLocalFiltersRoute)
.add(transactionsLocalFiltersRoute)
.add(serviceNodesLocalFiltersRoute)
.add(uiFiltersEnvironmentsRoute);
.add(uiFiltersEnvironmentsRoute)
.add(serviceMapRoute);
return api;
};

View file

@ -14,6 +14,7 @@ import { getServiceTransactionTypes } from '../lib/services/get_service_transact
import { getServiceNodeMetadata } from '../lib/services/get_service_node_metadata';
import { createRoute } from './create_route';
import { uiFiltersRt, rangeRt } from './default_api_types';
import { getServiceMap } from '../lib/services/map';
export const servicesRoute = createRoute(core => ({
path: '/api/apm/services',
@ -80,3 +81,18 @@ export const serviceNodeMetadataRoute = createRoute(() => ({
return getServiceNodeMetadata({ setup, serviceName, serviceNodeName });
}
}));
export const serviceMapRoute = createRoute(() => ({
path: '/api/apm/service-map',
params: {
query: rangeRt
},
handler: async (request, _response, hapi) => {
const setup = await setupRequest(request);
if (setup.config.get('xpack.apm.serviceMapEnabled')) {
return getServiceMap();
} else {
return hapi.response().code(404);
}
}
}));

View file

@ -0,0 +1,7 @@
/*
* 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.
*/
declare module 'cytoscape-dagre';

View file

@ -50,6 +50,7 @@
"@types/cheerio": "^0.22.10",
"@types/chroma-js": "^1.4.2",
"@types/color": "^3.0.0",
"@types/cytoscape": "^3.8.2",
"@types/d3-array": "^1.2.7",
"@types/d3-scale": "^2.1.1",
"@types/d3-shape": "^1.3.1",
@ -234,6 +235,8 @@
"copy-to-clipboard": "^3.0.8",
"content-disposition": "0.5.3",
"cronstrue": "^1.51.0",
"cytoscape": "^3.10.0",
"cytoscape-dagre": "^2.2.2",
"d3": "3.5.17",
"d3-scale": "1.0.7",
"dataloader": "^1.4.0",

118
yarn.lock
View file

@ -3164,6 +3164,11 @@
"@types/cp-file" "*"
"@types/glob" "*"
"@types/cytoscape@^3.8.2":
version "3.8.2"
resolved "https://registry.yarnpkg.com/@types/cytoscape/-/cytoscape-3.8.2.tgz#428e85e12fb8dba94b05b1b1a8b04fd6f91b9c2d"
integrity sha512-b9n8dwMnU+64++Vky7bfab3Fod6JRbhZRrRJgnyKd03sh/vgNYHsq9N3W1MlU32d3AanxWUDH/1+jC+l5V9BeQ==
"@types/d3-array@^1.2.7":
version "1.2.7"
resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-1.2.7.tgz#34dc654d34fc058c41c31dbca1ed68071a8fcc17"
@ -5761,7 +5766,7 @@ async@2.4.0:
dependencies:
lodash "^4.14.0"
async@2.6.1, async@^2.6.0, async@^2.6.1:
async@2.6.1, async@^2.5.0, async@^2.6.0, async@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610"
integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==
@ -9297,6 +9302,21 @@ cypress@^3.4.1:
url "0.11.0"
yauzl "2.10.0"
cytoscape-dagre@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/cytoscape-dagre/-/cytoscape-dagre-2.2.2.tgz#5f32a85c0ba835f167efee531df9e89ac58ff411"
integrity sha512-zsg36qNwua/L2stJSWkcbSDcvW3E6VZf6KRe6aLnQJxuXuz89tMqI5EVYVKEcNBgzTEzFMFv0PE3T0nD4m6VDw==
dependencies:
dagre "^0.8.2"
cytoscape@^3.10.0:
version "3.10.0"
resolved "https://registry.yarnpkg.com/cytoscape/-/cytoscape-3.10.0.tgz#3b462e0d35121ecd2d2702f470915fd6dae01777"
integrity sha512-lWOnG4HJQD0cy+tCiBmbV/QRknInuZ8HvjcUifQZ7E4LWmKMvl6d5eP0LaaRLfBJAplXWcJfwc17ZJ/nwPeaYg==
dependencies:
heap "^0.2.6"
lodash.debounce "^4.0.8"
d3-array@1, d3-array@^1.1.1, d3-array@^1.2.0, d3-array@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f"
@ -9549,6 +9569,14 @@ d@1:
dependencies:
es5-ext "^0.10.9"
dagre@^0.8.2:
version "0.8.4"
resolved "https://registry.yarnpkg.com/dagre/-/dagre-0.8.4.tgz#26b9fb8f7bdc60c6110a0458c375261836786061"
integrity sha512-Dj0csFDrWYKdavwROb9FccHfTC4fJbyF/oJdL9LNZJ8WUvl968P6PAKEriGqfbdArVJEmmfA+UyumgWEwcHU6A==
dependencies:
graphlib "^2.1.7"
lodash "^4.17.4"
damerau-levenshtein@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz#03191c432cb6eea168bb77f3a55ffdccb8978514"
@ -11356,7 +11384,12 @@ eslint-scope@^4.0.3:
esrecurse "^4.1.0"
estraverse "^4.1.1"
eslint-utils@^1.3.1, eslint-utils@^1.4.2:
eslint-utils@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512"
integrity sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==
eslint-utils@^1.4.2:
version "1.4.2"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab"
integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==
@ -13799,6 +13832,13 @@ graceful-fs@~1.1:
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=
graphlib@^2.1.7:
version "2.1.7"
resolved "https://registry.yarnpkg.com/graphlib/-/graphlib-2.1.7.tgz#b6a69f9f44bd9de3963ce6804a2fc9e73d86aecc"
integrity sha512-TyI9jIy2J4j0qgPmOOrHTCtpPqJGN/aurBwc6ZT+bRii+di1I+Wv3obRhVrmBEXet+qkMaEX67dXrwsd3QQM6w==
dependencies:
lodash "^4.17.5"
graphql-anywhere@^4.1.0-alpha.0:
version "4.1.16"
resolved "https://registry.yarnpkg.com/graphql-anywhere/-/graphql-anywhere-4.1.16.tgz#82bb59643e30183cfb7b485ed4262a7b39d8a6c1"
@ -14314,7 +14354,18 @@ handlebars@4.3.5:
optionalDependencies:
uglify-js "^3.1.4"
handlebars@^4.0.1, handlebars@^4.1.2:
handlebars@^4.0.1:
version "4.0.12"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5"
integrity sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA==
dependencies:
async "^2.5.0"
optimist "^0.6.1"
source-map "^0.6.1"
optionalDependencies:
uglify-js "^3.1.4"
handlebars@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67"
integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==
@ -14616,6 +14667,11 @@ header-case@^1.0.0:
no-case "^2.2.0"
upper-case "^1.1.3"
heap@^0.2.6:
version "0.2.6"
resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac"
integrity sha1-CH4fELBGky/IWU3Z5tN4r8nR5aw=
heavy@6.x.x:
version "6.1.0"
resolved "https://registry.yarnpkg.com/heavy/-/heavy-6.1.0.tgz#1bbfa43dc61dd4b543ede3ff87db8306b7967274"
@ -16990,7 +17046,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
js-yaml@3.13.1, js-yaml@3.x, js-yaml@^3.10.0, js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.4.6, js-yaml@^3.5.1, js-yaml@^3.5.4, js-yaml@^3.9.0, js-yaml@~3.13.0, js-yaml@~3.13.1, js-yaml@~3.7.0:
js-yaml@3.13.1, js-yaml@3.x, js-yaml@^3.10.0, js-yaml@^3.13.1, js-yaml@^3.4.6, js-yaml@^3.5.1, js-yaml@^3.5.4, js-yaml@^3.9.0, js-yaml@~3.13.0, js-yaml@~3.13.1, js-yaml@~3.7.0:
version "3.13.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
@ -16998,6 +17054,14 @@ js-yaml@3.13.1, js-yaml@3.x, js-yaml@^3.10.0, js-yaml@^3.13.0, js-yaml@^3.13.1,
argparse "^1.0.7"
esprima "^4.0.0"
js-yaml@^3.13.0:
version "3.13.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.0.tgz#38ee7178ac0eea2c97ff6d96fff4b18c7d8cf98e"
integrity sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"
jsbn@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
@ -25201,10 +25265,20 @@ set-immediate-shim@^1.0.0, set-immediate-shim@~1.0.1:
resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=
set-value@^2.0.0, set-value@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==
set-value@^0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1"
integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE=
dependencies:
extend-shallow "^2.0.1"
is-extendable "^0.1.1"
is-plain-object "^2.0.1"
to-object-path "^0.3.0"
set-value@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274"
integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==
dependencies:
extend-shallow "^2.0.1"
is-extendable "^0.1.1"
@ -25498,9 +25572,9 @@ snapdragon-util@^3.0.1:
kind-of "^3.2.0"
snapdragon@^0.8.1:
version "0.8.2"
resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==
version "0.8.1"
resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.1.tgz#e12b5487faded3e3dea0ac91e9400bf75b401370"
integrity sha1-4StUh/re0+PeoKyR6UAL91tAE3A=
dependencies:
base "^0.11.1"
debug "^2.2.0"
@ -25509,7 +25583,7 @@ snapdragon@^0.8.1:
map-cache "^0.2.2"
source-map "^0.5.6"
source-map-resolve "^0.5.0"
use "^3.1.0"
use "^2.0.0"
sntp@1.x.x:
version "1.0.9"
@ -28237,14 +28311,14 @@ union-find@^1.0.0:
integrity sha1-KSusQV5q06iVNdI3AQ20pTYoTlg=
union-value@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==
version "1.0.0"
resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4"
integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=
dependencies:
arr-union "^3.1.0"
get-value "^2.0.6"
is-extendable "^0.1.1"
set-value "^2.0.1"
set-value "^0.4.3"
uniq@^1.0.1:
version "1.0.1"
@ -28523,10 +28597,14 @@ url@0.11.0, url@^0.11.0:
punycode "1.3.2"
querystring "0.2.0"
use@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
use@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/use/-/use-2.0.2.tgz#ae28a0d72f93bf22422a18a2e379993112dec8e8"
integrity sha1-riig1y+TvyJCKhii43mZMRLeyOg=
dependencies:
define-property "^0.2.5"
isobject "^3.0.0"
lazy-cache "^2.0.2"
user-home@^2.0.0:
version "2.0.0"