Merge pull request #16 from TinyAllen/develop
Merge from Develop branch
diff --git a/README.md b/README.md
index e8d46b3..6b81b51 100644
--- a/README.md
+++ b/README.md
@@ -83,10 +83,10 @@
### Running the docker image
```
-docker run -p 8080:80 -d -e skywalking_collector=127.0.0.1:1234,127.0.0.1:1235 rocketbot
+docker run -p 8080:80 -d -e SKYWALKING_URL=127.0.0.1:1234,127.0.0.1:1235 rocketbot
```
-`skywalking_collector` is the address of your backend, multiple IP is changed by comma.
+`SKYWALKING_URL` is the address of your backend, multiple IP is changed by comma.
The default frontend address is `http://localhost:8080`.
@@ -141,3 +141,10 @@
Copyright © 2018, [Allen Wang](https://github.com/TinyAllen). Released under the [MIT](http://opensource.org/licenses/MIT) License.
+## Who Uses Rocketbot?
+按照登记顺序排序,更多接入公司,欢迎在 [https://github.com/TinyAllen/rocketbot/issues/15](https://github.com/TinyAllen/rocketbot/issues/15) 登记(仅供开源用户参考)
+<p>
+<img src="https://daoweb-resource.daocloud.io/logo/daocloud-logo-gray-account.svg" height="40px">
+<img src="http://springcloud.cn/default/img/logo.png" height="40px">
+<img src="https://user-images.githubusercontent.com/19775780/47834441-7c21d080-ddda-11e8-9e3a-67c43ab074bf.png" height="40px" >
+</p>
\ No newline at end of file
diff --git a/src/assets/lib.scss b/src/assets/lib.scss
index d08d5bd..9e8219e 100644
--- a/src/assets/lib.scss
+++ b/src/assets/lib.scss
@@ -30,8 +30,8 @@
.mb10{margin-bottom:10px;}
.mb15{margin-bottom:15px;}
.mb20{margin-bottom:20px;}
-.half{box-sizing: border-box;display:inline-block;width: 50%;padding-right: 20px;vertical-align: top;}
-
+.half{word-break: break-all;word-wrap: break-word;box-sizing: border-box;display:inline-block;width: 50%;padding-right: 20px;vertical-align: top;}
+.trans{transition:all .3s;}
.two-fifth{
box-sizing: border-box;
display:inline-block;
@@ -50,6 +50,24 @@
word-break: break-all;
word-wrap: break-word;
}
+.one-fifth{
+ box-sizing: border-box;
+ display:inline-block;
+ width: 20%;
+ padding-right: 20px;
+ vertical-align: top;
+ word-break: break-all;
+ word-wrap: break-word;
+}
+.four-fifth{
+ box-sizing: border-box;
+ display:inline-block;
+ width: 80%;
+ padding-right: 20px;
+ vertical-align: top;
+ word-break: break-all;
+ word-wrap: break-word;
+}
.link-hover{
transition: color .3s;
&:hover{
diff --git a/src/assets/style.scss b/src/assets/style.scss
index 7ffce30..8850f0c 100644
--- a/src/assets/style.scss
+++ b/src/assets/style.scss
@@ -37,4 +37,6 @@
padding-right: 0;
}
}
-
+.ivu-tooltip-popper{
+ word-break: break-all;
+}
diff --git a/src/store/modules/topo.ts b/src/store/modules/topo.ts
index dc09384..80a4072 100644
--- a/src/store/modules/topo.ts
+++ b/src/store/modules/topo.ts
@@ -1,6 +1,7 @@
import { Commit, ActionTree } from 'vuex';
import { getTopo, getTopoApp, getClusterBrief } from '@/api/topo';
import * as types from '../mutation-types';
+import Axios from 'axios';
interface Option {
key: String;
label: String;
@@ -13,7 +14,7 @@
source: String;
target: String;
}
-interface Node{
+interface Node {
apdex: Number;
avgResponseTime: Number;
cpm: Number;
@@ -26,7 +27,7 @@
sla: Number;
type: String;
}
-interface Cluster{
+interface Cluster {
numOfApplication: Number;
numOfService: Number;
numOfDatabase: Number;
@@ -37,14 +38,14 @@
export interface State {
calls: Call[];
nodes: Node[];
- cluster : Cluster;
- current : Option;
+ cluster: Cluster;
+ current: Option;
}
const initState: State = {
calls: [],
nodes: [],
- current : {
+ current: {
key: 'default',
label: 'default',
},
@@ -84,25 +85,35 @@
// actions
const actions: ActionTree<State, any> = {
- SET_TOPO_CURRENT(context: { commit: Commit; state: State, rootState: any }, data: Option) {
+ SET_TOPO_CURRENT(
+ context: { commit: Commit; state: State; rootState: any },
+ data: Option,
+ ) {
context.commit(types.SET_TOPO_CURRENT, data);
},
- GET_TOPO(context: { commit: Commit; state: State, rootState: any }) {
+ GET_TOPO(context: { commit: Commit; state: State; rootState: any }) {
return getTopo(context.rootState.global.duration).then((res) => {
context.commit(types.SET_TOPO, res.data.data.getClusterTopology);
});
+ // context.commit(types.SET_TOPO, data.data.getClusterTopology);
},
- GET_TOPO_APPLICATION(context: { commit: Commit; state: State, rootState: any }, applicationId:String) {
- return getTopoApp({ duration: context.rootState.global.duration, applicationId }).then((res) => {
+ GET_TOPO_APPLICATION(
+ context: { commit: Commit; state: State; rootState: any },
+ applicationId: String,
+ ) {
+ return getTopoApp({
+ duration: context.rootState.global.duration,
+ applicationId,
+ }).then((res) => {
context.commit(types.SET_TOPO, res.data.data.getApplicationTopology);
});
},
- GET_CLUSTER(context: { commit: Commit; state: State, rootState: any }) {
+ GET_CLUSTER(context: { commit: Commit; state: State; rootState: any }) {
return getClusterBrief(context.rootState.global.duration).then((res) => {
context.commit(types.SET_CLUSTER, res.data.data.getClusterBrief);
});
},
- CLEAR_TOPO(context: { commit: Commit; state: State, rootState: any }) {
+ CLEAR_TOPO(context: { commit: Commit; state: State; rootState: any }) {
context.commit(types.CLEAR_TOPO);
},
};
diff --git a/src/store/modules/trace.ts b/src/store/modules/trace.ts
index 23309af..12a1006 100644
--- a/src/store/modules/trace.ts
+++ b/src/store/modules/trace.ts
@@ -32,18 +32,17 @@
};
// getters
-const getters = {
-};
+const getters = {};
// mutations
const mutations = {
[types.SET_TRACE](state: State, data: Trace[]) {
state.traces = data;
},
- [types.SET_TRACE_TOTAL](state: State, total:Number) {
+ [types.SET_TRACE_TOTAL](state: State, total: Number) {
state.tracesTotal = total;
},
- [types.SET_SPAN](state: State, data:Span[]) {
+ [types.SET_SPAN](state: State, data: Span[]) {
state.spans = data;
},
[types.CLEAR_TRACE](state: State) {
@@ -54,19 +53,29 @@
// actions
const actions: ActionTree<State, any> = {
- GET_TRACES(context: { commit: Commit; state: State, rootState: any }, params:String) {
+ GET_TRACES(
+ context: { commit: Commit; state: State; rootState: any },
+ params: String,
+ ) {
return getTraces(params).then((res) => {
context.commit(types.SET_TRACE, res.data.data.queryBasicTraces.traces);
- context.commit(types.SET_TRACE_TOTAL, res.data.data.queryBasicTraces.total);
+ context.commit(
+ types.SET_TRACE_TOTAL,
+ res.data.data.queryBasicTraces.total,
+ );
});
},
- GET_SPANS(context: { commit: Commit; state: State, rootState: any }, params:String) {
+ GET_SPANS(
+ context: { commit: Commit; state: State; rootState: any },
+ params: String,
+ ) {
context.commit(types.SET_SPAN, []);
- return getTraceSpans(params).then((res) => {
+ return getTraceSpans(params).then((res) => {
+ // context.commit(types.SET_SPAN, span.data.queryTrace.spans);
context.commit(types.SET_SPAN, res.data.data.queryTrace.spans);
});
},
- CLEAR_TRACE(context: { commit: Commit; state: State, rootState: any }) {
+ CLEAR_TRACE(context: { commit: Commit; state: State; rootState: any }) {
context.commit(types.CLEAR_TRACE);
},
};
diff --git a/src/views/components/dashboard/slow-service.vue b/src/views/components/dashboard/slow-service.vue
index 18e40dd..ad94dae 100644
--- a/src/views/components/dashboard/slow-service.vue
+++ b/src/views/components/dashboard/slow-service.vue
@@ -4,7 +4,7 @@
<div>
<span class="r sm">{{i.value}} ms</span>
<div class="mb5 cp link-hover" @click="changeService(i)" >
- <Tooltip :content="i.service.label" placement="top" class="ell" style="max-width: 160px;">
+ <Tooltip :content="i.service.label" max-width="200" placement="top" class="ell" style="max-width: 200px;">
<span>{{i.service.label}}</span>
</Tooltip>
</div>
diff --git a/src/views/components/dashboard/top-slow.vue b/src/views/components/dashboard/top-slow.vue
index af0a2c1..c2b2d8b 100644
--- a/src/views/components/dashboard/top-slow.vue
+++ b/src/views/components/dashboard/top-slow.vue
@@ -4,7 +4,7 @@
<div>
<span class="r sm">{{i.duration}} ms</span>
<div class="blue cp mb5" @click="$router.push({ path:'/trace/link', query:{traces:i.traceIds.join('&')}})">
- <Tooltip :content="i.operationNames[0]" placement="top" class="ell" style="max-width: 160px;">
+ <Tooltip :content="`${moment(parseInt(i.start)).format('YYYY-MM-DD HH:mm:ss')}\n${i.operationNames[0]}`" placement="top" max-width="200" class="ell" style="max-width: 200px;">
<span>{{i.operationNames[0]}}</span>
</Tooltip>
</div>
@@ -17,11 +17,13 @@
<script lang="ts">
import Vue from 'vue';
import { State } from 'vuex-class';
+import moment from 'dayjs';
import { Component } from 'vue-property-decorator';
@Component({})
export default class RkChartBox extends Vue {
@State('dashboard') stateDashboard;
+ moment = moment;
get maxDuration() {
const temp:Number[] = [...this.stateDashboard.slowTrace].map(i => i.duration);
return Math.max.apply(null, temp);
diff --git a/src/views/components/dashboard/top-throughput.vue b/src/views/components/dashboard/top-throughput.vue
index 0a5a325..0604a8d 100644
--- a/src/views/components/dashboard/top-throughput.vue
+++ b/src/views/components/dashboard/top-throughput.vue
@@ -4,7 +4,7 @@
<div>
<span class="r sm">{{i.value}} calls/ m</span>
<div class="mb5 cp link-hover" @click="appChange(i)">
- <Tooltip :content="i.label" placement="top" class="ell" style="max-width: 160px;">
+ <Tooltip :content="i.label" max-width="200" placement="top" class="ell" style="max-width: 200px;">
<span>{{i.label}}</span>
</Tooltip>
</div>
diff --git a/src/views/components/topology/topo.vue b/src/views/components/topology/topo.vue
index 265d446..1a9bc81 100644
--- a/src/views/components/topology/topo.vue
+++ b/src/views/components/topology/topo.vue
@@ -173,6 +173,13 @@
},
methods: {
draw() {
+ const codeId = this.datas.nodes.map(i => i.id);
+ for (let i = 0; i < this.datas.calls.length; i += 1) {
+ const element = this.datas.calls[i];
+ if(codeId.indexOf(element.target) === -1 ) {
+ this.datas.calls[i].target = this.datas.calls[i].source;
+ }
+ }
this.svg.select('.graph').remove();
this.force = d3
.forceSimulation(this.datas.nodes)
@@ -188,6 +195,10 @@
this.svg.call(this.getZoomBehavior(this.graph));
this.svg.on('click', (d, i) => {
this.$emit('setCurrentApp', {name: '', id: ''});
+ this.toggleNode(this.node, d, false);
+ this.toggleLine(this.line, d, false);
+ // this.toggleMarker(marker, currNode, true);
+ this.toggleLineText(this.linkText, d, false);
});
this.defs = this.graph.append('defs');
this.arrowMarker = this.defs
@@ -203,7 +214,9 @@
const arrow_path = 'M2,2 L10,6 L2,10 L6,6 L2,2';
this.glink = this.graph.append('g').selectAll('.link');
this.link = this.glink.data(this.datas.calls).enter().append('g');
- this.line = this.link.append('path').attr('class', 'link').attr("marker-end","url(#arrow)");
+ this.line = this.link.append('path').attr('class', 'link')
+ .attr('stroke-dasharray', d => d.cpm ? '30 3': '0')
+ .attr('stroke', d => d.cpm ? 'rgba(255, 199, 31, 0.4)' : 'rgba(199, 199, 210, 0.3)').attr("marker-end","url(#arrow)");
this.linkText = this.link.append('g');
this.linkText
.append('rect')
@@ -245,6 +258,10 @@
delete copyD.fy;
delete copyD.index;
that.$emit('setCurrentApp', copyD);
+ that.toggleNode(that.node, d, true);
+ that.toggleLine(that.line, d, true);
+ // this.toggleMarker(marker, currNode, true);
+ that.toggleLineText(that.linkText, d, true);
});
this.node
.append('rect')
@@ -296,6 +313,65 @@
}
});
},
+ isLinkNode(currNode, node) {
+ if (currNode.id === node.id) {
+ return true;
+ }
+ return this.datas.calls.filter(i =>
+ (i.source.id === currNode.id || i.target.id === currNode.id) &&
+ (i.source.id === node.id || i.target.id === node.id)
+ ).length;
+ },
+ toggleNode(nodeCircle, currNode, isHover) {
+ if (isHover) {
+ // 提升节点层级
+ nodeCircle.sort((a, b) => a.id === currNode.id ? 1 : -1);
+ nodeCircle
+ .style('opacity', .2)
+ .filter(node => this.isLinkNode(currNode, node))
+ .style('opacity', 1);
+ } else {
+ nodeCircle.style('opacity', 1);
+ }
+},
+toggleLine(linkLine, currNode, isHover) {
+ if (isHover) {
+ linkLine
+ .style('opacity', .05)
+ .style('animation', 'none')
+ .filter(link => this.isLinkLine(currNode, link))
+ .style('opacity', 1)
+ .style('animation', 'dash 6s linear infinite');
+ // .classed('link-active', true);
+ } else {
+ linkLine
+ .style('opacity', 1)
+ .style('animation', 'dash 6s linear infinite');
+ // .classed('link-active', false);
+ }
+ },
+isLinkLine(node, link) {
+ return link.source.id == node.id || link.target.id == node.id;
+},
+toggleLineText(lineText, currNode, isHover) {
+ if (isHover) {
+ lineText
+ .style('fill-opacity', link => this.isLinkLine(currNode, link) ? 1.0 : 0.0);
+ } else {
+ lineText
+ .style('fill-opacity', '1.0');
+ }
+ },
+ toggleMarker(marker, currNode, isHover) {
+ if (isHover) {
+ marker.filter(link => this.isLinkLine(currNode, link))
+ .style('transform', 'scale(1.5)');
+ } else {
+ marker
+ .attr('refX', nodeConf.radius.Company)
+ .style('transform', 'scale(1)');
+ }
+ },
resize() {
this.svg.attr('width', this.$refs.topo.offsetWidth);
this.svg.attr('height', document.body.clientHeight - 64);
@@ -313,7 +389,6 @@
);
this.linkText.attr('transform',d => {
let tagx = 1
- // if(d.sx < d.tx) tagx = -tagx;
return `translate(${d.sx - (d.sx-d.tx)/2}, ${d.sy - (d.sy-d.ty)/2})`
});
this.node.attr('transform', d => `translate(${d.x},${d.y - 20})`);
@@ -332,7 +407,6 @@
});
},
dragstart(d) {
- // console.log(this.node)
this.node._groups[0].forEach(d => {
d.__data__.fx = d.__data__.x;
d.__data__.fy = d.__data__.y;
@@ -367,8 +441,6 @@
.link {
stroke-linecap: round;
fill:rgba(255, 255, 255, 0);
- stroke: rgba(255, 199, 31, 0.5);
- stroke-dasharray: 30 3;
animation: dash 6s linear infinite;
}
@keyframes dash {
@@ -381,9 +453,9 @@
}
.link2 {
stroke: rgb(80, 80, 80);
- stroke-dasharray: 200 20;
- stroke-dashoffset: 0;
- animation: dash 1.5s linear infinite;
+ // stroke-dasharray: 200 20;
+ // stroke-dashoffset: 0;
+ // animation: dash 1.5s linear infinite;
}
@keyframes dash {
from {
diff --git a/src/views/components/trace/d3-trace.js b/src/views/components/trace/d3-trace.js
index 36c54f0..d544d62 100644
--- a/src/views/components/trace/d3-trace.js
+++ b/src/views/components/trace/d3-trace.js
@@ -5,6 +5,8 @@
Http: '#72a5fd',
Database: '#ff6732',
Unknown: '#ffc107',
+ Cache: '#00bcd4',
+ RPCFramework: '#ee4395',
};
const trace = (data,width,row,vm) => {
d3.select('svg').remove();
@@ -61,8 +63,8 @@
nodeEnter.append('text').attr('dy', 2).attr('dx', 12)
.style('fill', d => d.data.isError? '#f1483f' : '')
.text(d => d.data.isError? 'x' : '');
- nodeEnter.append('text').style('fill', d => type[d.data.layer]).style('stroke', d => type[d.data.layer]).style('stroke-width', '0.8').style('font-size', '11px').attr('dy', 2)
- .attr('dx', d => d.data.label.length > 50 ? 320 : 40 + d.data.label.length * 6.9)
+ nodeEnter.append('text').style('fill', d => type[d.data.layer]).style('stroke', d => type[d.data.layer]).style('stroke-width', '0.6').style('font-size', '11px').attr('dy', 2)
+ .attr('dx', d => d.data.label.length > 50 ? 320 : 45 + d.data.label.length * 6.9)
.text(d => d.data.layer);
nodeEnter.append('text').attr('dy', 20).attr('dx', 30).style('fill', '#acacac').style('font-size', '11px')
.text(d => `${d.data.applicationCode? d.data.applicationCode : ''} ${d.data.component? `> ${d.data.component}` : ''}`);
diff --git a/src/views/components/trace/trace-charts.vue b/src/views/components/trace/trace-charts.vue
index 781cbaa..5280448 100644
--- a/src/views/components/trace/trace-charts.vue
+++ b/src/views/components/trace/trace-charts.vue
@@ -83,10 +83,11 @@
this.traverseTree(segmentGroup[ref.parentSegmentId],ref.parentSpanId,ref.parentSegmentId,segmentGroup[id])
};
})
- if(segmentGroup[id].refs.length !==0 ) delete segmentGroup[id];
+ // if(segmentGroup[id].refs.length !==0 ) delete segmentGroup[id];
})
for (let i in segmentGroup) {
- this.segmentId.push(segmentGroup[i])
+ if(segmentGroup[i].refs.length ===0 )
+ this.segmentId.push(segmentGroup[i]);
}
trace({label:`TraceID: ${this.traceId}`, children: this.segmentId},this.$el.offsetWidth, this.data,this);
},
diff --git a/src/views/containers/topology.vue b/src/views/containers/topology.vue
index 6f0ddf9..11b9927 100644
--- a/src/views/containers/topology.vue
+++ b/src/views/containers/topology.vue
@@ -3,20 +3,23 @@
<TopoChart :datas="stateTopo" @setCurrentApp="setCurrentApp"/>
<div class="topology-select">
</div>
- <div class="topology-board" v-if="this.current.id">
+ <div class="topology-board" v-if="this.current.id" v-show="open">
<div class="mb10" v-for="(value,key) in current" :key="key"><span class="half">{{key}}:</span><span class="half">{{value}}</span></div>
</div>
- <div class="topology-board" v-else>
+ <div class="topology-board" v-else v-show="open">
<div class="mb10"><span class="half">Application</span><span class="half">{{stateTopo.cluster.numOfApplication}}</span></div>
<div class="mb10"><span class="half">DB & Cache</span><span class="half">{{stateTopo.cluster.numOfDatabase + stateTopo.cluster.numOfCache}}</span></div>
<div class="mb10"><span class="half">Service</span><span class="half">{{stateTopo.cluster.numOfService}}</span></div>
<div class="mb10"><span class="half">MQ</span><span class="half">{{stateTopo.cluster.numOfMQ}}</span></div>
</div>
- <div v-clickout="() => this.show = false">
- <div class="topology-setting-btn" @click="show = true">
+ <div v-clickout="() => this.show = false" >
+ <div class="topology-setting-btn" @click="open = !open" :style="`right:${open?345:25}px`">
+ <Icon :type="open?'ios-arrow-forward':'ios-arrow-back'" style="vertical-align: initial;"/>
+ </div>
+ <div class="topology-setting-btn" @click="show = true" style="top:75px" :style="`right:${open?345:25}px`">
<Icon type="md-settings" style="vertical-align: initial;"/>
</div>
- <div @click="routerGo" class="topology-setting-btn" v-if="this.current.avgResponseTime | this.current.cpm | this.current.sla" style="top:75px">
+ <div @click="routerGo" class="topology-setting-btn" :style="`right:${open?345:25}px`" v-if="this.current.avgResponseTime | this.current.cpm | this.current.sla" style="top:125px">
<Icon type="md-cube" style="vertical-align: initial;"/>
</div>
<TopoTool :stateTopo="stateTopo" :stateOptions="stateOptions" :show.sync="show" :propsTime="stateGlobal.duration"/>
@@ -45,6 +48,7 @@
id: '',
name: '',
};
+ open = true;
show = false;
beforeMount() {
this.SET_EVENTS([this.getCluster, getTopo]);
@@ -91,7 +95,6 @@
cursor: pointer;
position:absolute;
top:25px;
- right:345px;
height: 36px;
width: 36px;
text-align: center;
diff --git a/src/views/containers/trace-detail.vue b/src/views/containers/trace-detail.vue
index a87c33a..b1f9dd7 100644
--- a/src/views/containers/trace-detail.vue
+++ b/src/views/containers/trace-detail.vue
@@ -16,11 +16,20 @@
</div>
<div slot="inner" class="micro-panel-inner">
<div class="rk-trace-detail">
+ <h4 class="mb10">Tags.</h4>
+ <div class="mb15"><span class="mr10">Label:</span><span>{{this.currentSpan.label}}</span></div>
<div class="half mb15"><span class="two-fifth">Span Type:</span><span class="three-fifth">{{this.currentSpan.type}}</span></div>
<div class="half mb15"><span class="two-fifth">Component:</span><span class="three-fifth">{{this.currentSpan.component}}</span></div>
<div class="half mb15"><span class="two-fifth">Peer:</span><span class="three-fifth">{{this.currentSpan.peer||'No Peer'}}</span></div>
<div class="half mb15"><span class="two-fifth">Error:</span><span class="three-fifth">{{this.currentSpan.isError}}</span></div>
<div class="half mb15" v-for="i in this.currentSpan.tags" :key="i.key"><span class="two-fifth">{{i.key}}:</span><span class="three-fifth">{{i.value}}</span></div>
+ <h4 class="mb10" v-if="this.currentSpan.logs" v-show="this.currentSpan.logs.length">Logs.</h4>
+ <div v-for="(i, index) in this.currentSpan.logs" :key="index">
+ <div class="mb10 sm"><span class="mr10">Time:</span><span class="grey">{{i.time | dateformat}}</span></div>
+ <div class="mb15" v-for="(_i, _index) in i.data" :key="_index">
+ <span class="one-fifth">{{_i.key}}:</span><pre class="four-fifth mt0 mb0" style="font-size:12px">{{_i.value}}</pre>
+ </div>
+ </div>
</div>
</div>
</RkDrawer>