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 => `&yen; ${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.