You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@skywalking.apache.org by ha...@apache.org on 2018/03/03 14:12:58 UTC
[incubator-skywalking-ui] 01/01: Add new service dependency map
This is an automated email from the ASF dual-hosted git repository.
hanahmily pushed a commit to branch feature/dependency-map
in repository https://gitbox.apache.org/repos/asf/incubator-skywalking-ui.git
commit fcc934336080e87be6af3d0c3cd422ad7d01cc22
Author: gaohongtao <ha...@gmail.com>
AuthorDate: Sat Mar 3 22:12:19 2018 +0800
Add new service dependency map
---
mock/service.js | 14 ++---
src/components/Charts/Sankey/index.js | 103 ++++++++++++++++++++++++++++++++++
src/components/Charts/equal.js | 17 ------
src/components/Charts/index.js | 2 +
src/routes/Service/Service.js | 50 ++++++++++++-----
5 files changed, 149 insertions(+), 37 deletions(-)
diff --git a/mock/service.js b/mock/service.js
index 14a9df0..f2eefc9 100644
--- a/mock/service.js
+++ b/mock/service.js
@@ -34,7 +34,7 @@ export default {
'nodes|1-5': [
{
'id|+1': 100,
- name: '@name',
+ name: '@url',
'type|1': ['DUBBO', 'USER', 'SPRINGMVC'],
'calls|1000-2000': 1,
'sla|1-100.1-2': 1,
@@ -46,7 +46,7 @@ export default {
nodes: [
{
'id|+1': 1,
- name: '@name',
+ name: '@url',
'type|1': ['DUBBO', 'tomcat', 'SPRINGMVC'],
'calls|1000-2000': 1,
'sla|1-100.1-2': 1,
@@ -58,7 +58,7 @@ export default {
'nodes|2-5': [
{
'id|+1': 200,
- name: '@name',
+ name: '@url',
'type|1': ['Oracle', 'MYSQL', 'REDIS'],
},
],
@@ -67,16 +67,16 @@ export default {
const calls = upNodes.nodes.map(node => (mockjs.mock({
source: node.id,
target: 1,
- 'isAlarm|1': true,
+ 'isAlert|1': true,
'callType|1': ['rpc', 'http', 'dubbo'],
- 'callsPerSec|100-2000': 1,
+ 'callsPerSec|0-2000': 1,
'avgResponseTime|500-5000': 1,
}))).concat(downNodes.nodes.map(node => (mockjs.mock({
source: 1,
target: node.id,
- 'isAlarm|1': true,
+ 'isAlert|1': true,
'callType|1': ['rpc', 'http', 'dubbo'],
- 'callsPerSec|100-2000': 1,
+ 'callsPerSec|0-2000': 1,
'avgResponseTime|500-5000': 1,
}))));
return {
diff --git a/src/components/Charts/Sankey/index.js b/src/components/Charts/Sankey/index.js
new file mode 100644
index 0000000..828ad62
--- /dev/null
+++ b/src/components/Charts/Sankey/index.js
@@ -0,0 +1,103 @@
+import React, { Component } from 'react';
+import { Chart, Geom, Tooltip, View, Label } from 'bizcharts';
+import { DataSet } from '@antv/data-set';
+import autoHeight from '../autoHeight';
+import styles from '../index.less';
+
+@autoHeight()
+class Sankey extends Component {
+ static defaultProps = {
+ limitColor: 'rgb(255, 144, 24)',
+ color: 'rgb(24, 144, 255)',
+ };
+
+ handleRoot = (n) => {
+ this.root = n;
+ };
+
+ handleRef = (n) => {
+ this.node = n;
+ };
+
+ render() {
+ const {
+ height,
+ title,
+ forceFit = true,
+ data,
+ edgeColor = '#bbb',
+ edgeTooltip = ['target*source*value', (target, source, value) => {
+ return {
+ name: `${source.name} to ${target.name} </span>`,
+ value,
+ };
+ }],
+ } = this.props;
+
+ const ds = new DataSet();
+ const dv = ds.createView().source(data, {
+ type: 'graph',
+ });
+ dv.transform({
+ type: 'diagram.sankey',
+ });
+ const scale = {
+ x: {
+ sync: true,
+ },
+ y: {
+ sync: true,
+ },
+ };
+ console.log(dv);
+ return (
+ <div className={styles.chart} style={{ height }} ref={this.handleRoot}>
+ <div ref={this.handleRef}>
+ {title && <h4 style={{ marginBottom: 20 }}>{title}</h4>}
+ <Chart
+ forceFit={forceFit}
+ data={[1]}
+ height={title ? height - 41 : height}
+ scale={scale}
+ padding={[0, 400, 0, 0]}
+ >
+ <Tooltip showTitle={false} />
+ <View data={dv.edges}>
+ <Geom
+ type="edge"
+ position="x*y"
+ shape="arc"
+ color={edgeColor}
+ opacity={0.6}
+ tooltip={edgeTooltip}
+ />
+ </View>
+ <View data={dv.nodes}>
+ <Geom
+ type="polygon"
+ position="x*y"
+ color="name"
+ tooltip={false}
+ >
+ <Label
+ content="name"
+ textStyle={{
+ fill: '#545454',
+ textAlign: 'start',
+ }}
+ offset={0}
+ formatter={(val) => {
+ return ` ${val}`;
+ }
+ }
+ />
+ </Geom>
+ </View>
+ </Chart>
+ </div>
+ </div>
+ );
+ }
+}
+
+export default Sankey;
diff --git a/src/components/Charts/equal.js b/src/components/Charts/equal.js
deleted file mode 100644
index ff3a4c7..0000000
--- a/src/components/Charts/equal.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/* eslint eqeqeq: 0 */
-
-function equal(old, target) {
- let r = true;
- for (const prop in old) {
- if (typeof old[prop] === 'function' && typeof target[prop] === 'function') {
- if (old[prop].toString() != target[prop].toString()) {
- r = false;
- }
- } else if (old[prop] != target[prop]) {
- r = false;
- }
- }
- return r;
-}
-
-export default equal;
diff --git a/src/components/Charts/index.js b/src/components/Charts/index.js
index fed8db9..2af3afe 100644
--- a/src/components/Charts/index.js
+++ b/src/components/Charts/index.js
@@ -15,6 +15,7 @@ import WaterWave from './WaterWave';
import TagCloud from './TagCloud';
import TimelineChart from './TimelineChart';
import StackBar from './StackBar';
+import Sankey from './Sankey';
const yuan = val => `¥ ${numeral(val).format('0,0')}`;
@@ -35,4 +36,5 @@ export {
Line,
Area,
StackBar,
+ Sankey,
};
diff --git a/src/routes/Service/Service.js b/src/routes/Service/Service.js
index 7bdba79..ac0a3aa 100644
--- a/src/routes/Service/Service.js
+++ b/src/routes/Service/Service.js
@@ -1,11 +1,10 @@
import React, { PureComponent } from 'react';
import { connect } from 'dva';
-import { Row, Col, Card, Form } from 'antd';
+import { Row, Col, Form } from 'antd';
import {
- ChartCard, MiniArea, MiniBar,
+ ChartCard, MiniArea, MiniBar, Sankey,
} from '../../components/Charts';
import { axis } from '../../utils/time';
-import { ServiceTopology } from '../../components/Topology';
import { Panel, Search } from '../../components/Page';
const { Item: FormItem } = Form;
@@ -48,6 +47,40 @@ export default class Service extends PureComponent {
}
avg = list => (list.length > 0 ?
(list.reduce((acc, curr) => acc + curr) / list.length).toFixed(2) : 0)
+ renderSankey = (data) => {
+ if (data.nodes.length < 2) {
+ return <span style={{ display: 'none' }} />;
+ }
+ const nodesMap = new Map();
+ data.nodes.forEach((_, i) => {
+ nodesMap.set(`${_.id}`, i);
+ });
+ const nData = {
+ nodes: data.nodes,
+ edges: data.calls.filter(_ => _.callsPerSec * _.avgResponseTime > 0).map(_ =>
+ ({ ..._, value: _.callsPerSec * _.avgResponseTime, source: nodesMap.get(`${_.source}`), target: nodesMap.get(`${_.target}`) })),
+ };
+ return (
+ <Row gutter={24}>
+ <Col xs={24} sm={24} md={24} lg={24} xl={24} style={{ marginTop: 24 }}>
+ <ChartCard
+ title="Dependency Map"
+ contentHeight={200}
+ >
+ <Sankey
+ data={nData}
+ edgeTooltip={['target*source*callsPerSec*avgResponseTime*isAlert', (target, source, callsPerSec, avgResponseTime) => {
+ return {
+ name: `${source.name} to ${target.name} </span>`,
+ value: `${callsPerSec} calls/s ${avgResponseTime}ms`,
+ };
+ }]}
+ edgeColor={['isAlert', isAlert => (isAlert ? '#DC143C' : '#bbb')]}
+ />
+ </ChartCard>
+ </Col>
+ </Row>);
+ }
render() {
const { form, service, duration } = this.props;
const { getFieldDecorator } = form;
@@ -118,16 +151,7 @@ export default class Service extends PureComponent {
</ChartCard>
</Col>
</Row>
- <Row gutter={24}>
- <Col xs={24} sm={24} md={24} lg={24} xl={24} style={{ marginTop: 24 }}>
- <Card
- bordered={false}
- bodyStyle={{ padding: 0 }}
- >
- <ServiceTopology elements={getServiceTopology} layout={{ name: 'concentric', minNodeSpacing: 200 }} />
- </Card>
- </Col>
- </Row>
+ {this.renderSankey(getServiceTopology)}
</Panel>
</div>
);
--
To stop receiving notification emails like this one, please contact
hanahmily@apache.org.