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/09/10 08:40:54 UTC
[incubator-skywalking-ui] 01/02: Refactor endpoint page with v6
protocol
This is an automated email from the ASF dual-hosted git repository.
hanahmily pushed a commit to branch 6.0.0/dev
in repository https://gitbox.apache.org/repos/asf/incubator-skywalking-ui.git
commit 2fab03fff22ec23f78994ca16ade1cf6c827d875
Author: Gao Hongtao <ha...@gmail.com>
AuthorDate: Mon Sep 10 14:18:06 2018 +0800
Refactor endpoint page with v6 protocol
---
.roadhogrc.mock.js | 10 +-
mock/metadata.js | 10 +-
mock/metric.js | 8 ++
mock/topology.js | 49 ++++++++
src/common/menu.js | 4 +-
src/common/router.js | 4 +-
src/models/{service.js => endpoint.js} | 100 ++++++++--------
.../{Service/Service.js => Endpoint/Endpoint.js} | 128 ++++++++++-----------
src/utils/time.js | 5 +
src/utils/utils.js | 7 ++
10 files changed, 199 insertions(+), 126 deletions(-)
diff --git a/.roadhogrc.mock.js b/.roadhogrc.mock.js
index 9fa1e25..1021e7f 100644
--- a/.roadhogrc.mock.js
+++ b/.roadhogrc.mock.js
@@ -1,7 +1,7 @@
import mockjs from 'mockjs';
import fs from 'fs';
import { delay } from 'roadhog-api-doc';
-import { getTopology } from './mock/topology';
+import { getTopology, getServiceTopology } from './mock/topology';
import { getAllApplication, getApplication } from './mock/application';
import { searchServer, getServer } from './mock/server';
import { searchService, getService } from './mock/service';
@@ -9,8 +9,8 @@ import { Alarms, getNoticeAlarm, AlarmTrend } from './mock/alarm';
import { TraceBrief, Trace } from './mock/trace'
import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools';
import { graphql } from 'graphql';
-import { ClusterBrief, getAllServices } from './mock/metadata';
-import { Thermodynamic } from './mock/metric';
+import { ClusterBrief, getAllServices, searchEndpoint } from './mock/metadata';
+import { IntValues, Thermodynamic } from './mock/metric';
import { getTopN } from './mock/aggregation';
const noMock = process.env.NO_MOCK === 'true';
@@ -19,6 +19,8 @@ const resolvers = {
Query: {
getTopN,
getAllServices,
+ getServiceTopology,
+ searchEndpoint,
}
}
@@ -30,6 +32,7 @@ const schema = makeExecutableSchema({ typeDefs: [
fs.readFileSync('query-protocol/metric.graphqls', 'utf8'),
fs.readFileSync('query-protocol/aggregation.graphqls', 'utf8'),
fs.readFileSync('query-protocol/trace.graphqls', 'utf8'),
+ fs.readFileSync('query-protocol/topology.graphqls', 'utf8'),
], resolvers });
addMockFunctionsToSchema({
@@ -42,6 +45,7 @@ addMockFunctionsToSchema({
Alarms,
TraceBrief,
Trace,
+ IntValues,
},
preserveResolvers: true
});
diff --git a/mock/metadata.js b/mock/metadata.js
index 351f7f6..12fe2c3 100644
--- a/mock/metadata.js
+++ b/mock/metadata.js
@@ -28,8 +28,14 @@ export default {
,
getAllServices: () => {
const data = mockjs.mock({
- 'serviceId|20-50': [{ 'id|+1': 3, name: function() { return `app-${this.id}`; } }], // eslint-disable-line
+ 'serviceId|20-50': [{ 'id|+1': 3, name: function() { return `service-${this.id}`; } }], // eslint-disable-line
});
return data.serviceId;
- }
+ },
+ searchEndpoint: () => {
+ const data = mockjs.mock({
+ 'endpointId|20-50': [{ 'id|+1': 3, name: function() { return `endpoint-${this.id}`; } }], // eslint-disable-line
+ });
+ return data.endpointId;
+ },
};
diff --git a/mock/metric.js b/mock/metric.js
index 673cc63..410d006 100644
--- a/mock/metric.js
+++ b/mock/metric.js
@@ -30,4 +30,12 @@ export default {
},
responseTimeStep: 50,
}),
+ IntValues: () => (mockjs.mock(
+ {
+ 'values|60': [{
+ 'id|+1': 1,
+ value: '@natural(0, 1000)',
+ }],
+ }
+ )),
};
diff --git a/mock/topology.js b/mock/topology.js
index e0b816b..5480589 100644
--- a/mock/topology.js
+++ b/mock/topology.js
@@ -19,6 +19,55 @@
import mockjs from 'mockjs';
export default {
+ getServiceTopology: () => {
+ const upNodes = mockjs.mock({
+ 'nodes|1-5': [
+ {
+ 'id|+1': 100,
+ name: '@url',
+ 'type|1': ['DUBBO', 'USER', 'SPRINGMVC'],
+ },
+ ],
+ });
+ const centerNodes = mockjs.mock({
+ nodes: [
+ {
+ 'id|+1': 1,
+ name: '@url',
+ 'type|1': ['DUBBO', 'tomcat', 'SPRINGMVC'],
+ },
+ ],
+ });
+ const downNodes = mockjs.mock({
+ 'nodes|2-5': [
+ {
+ 'id|+1': 200,
+ name: '@url',
+ 'type|1': ['Oracle', 'MYSQL', 'REDIS'],
+ },
+ ],
+ });
+ downNodes.nodes.push({ id: -111 });
+ const nodes = upNodes.nodes.concat(centerNodes.nodes, downNodes.nodes);
+ const calls = upNodes.nodes.map(node => (mockjs.mock({
+ source: node.id,
+ target: 1,
+ 'isAlert|1': true,
+ 'callType|1': ['rpc', 'http', 'dubbo'],
+ 'cpm|0-1000': 1,
+ }))).concat(downNodes.nodes.map(node => (mockjs.mock({
+ source: 1,
+ target: node.id,
+ 'isAlert|1': true,
+ 'callType|1': ['rpc', 'http', 'dubbo'],
+ 'cpm|0-2000': 1,
+ }))));
+ calls.push({ source: '-175', target: 1, isAlert: false, callType: 'GRPC', cpm: 0, avgResponseTime: 52 });
+ return {
+ nodes,
+ calls,
+ };
+ },
getTopology(req, res) {
res.json(mockjs.mock(
{
diff --git a/src/common/menu.js b/src/common/menu.js
index cbf1815..bc98328 100644
--- a/src/common/menu.js
+++ b/src/common/menu.js
@@ -34,8 +34,8 @@ const menuData = [{
name: 'Application',
path: 'application',
}, {
- name: 'Service',
- path: 'service',
+ name: 'Endpoint',
+ path: 'endpoint',
}, {
name: 'Alarm',
path: 'alarm',
diff --git a/src/common/router.js b/src/common/router.js
index 00e3934..db30edd 100644
--- a/src/common/router.js
+++ b/src/common/router.js
@@ -100,8 +100,8 @@ export const getRouterData = (app) => {
'/monitor/application': {
component: dynamicWrapper(app, ['application'], () => import('../routes/Application/Application')),
},
- '/monitor/service': {
- component: dynamicWrapper(app, ['service'], () => import('../routes/Service/Service')),
+ '/monitor/endpoint': {
+ component: dynamicWrapper(app, ['endpoint'], () => import('../routes/Endpoint/Endpoint')),
},
'/trace': {
component: dynamicWrapper(app, ['trace'], () => import('../routes/Trace/Trace')),
diff --git a/src/models/service.js b/src/models/endpoint.js
similarity index 64%
rename from src/models/service.js
rename to src/models/endpoint.js
index bd873ec..662546a 100644
--- a/src/models/service.js
+++ b/src/models/endpoint.js
@@ -16,12 +16,12 @@
*/
-import { generateModal, saveOptionsInState } from '../utils/models';
-import { query } from '../services/graphql';
+import { base, saveOptionsInState } from '../utils/models';
+import { exec } from '../services/graphql';
const optionsQuery = `
- query ApplicationOption($duration: Duration!) {
- applicationId: getAllApplication(duration: $duration) {
+ query ServiceOption($duration: Duration!) {
+ serviceId: getAllServices(duration: $duration) {
key: id
label: name
}
@@ -29,15 +29,30 @@ const optionsQuery = `
`;
const dataQuery = `
- query Service($serviceId: ID!, $duration: Duration!, $traceCondition: TraceQueryCondition!) {
- getServiceResponseTimeTrend(serviceId: $serviceId, duration: $duration) {
- trendList
+ query Endpoint($endpointId: ID!, $duration: Duration!, $traceCondition: TraceQueryCondition!) {
+ getEndpointResponseTimeTrend: getLinearIntValues(metric: {
+ name: "endpointResponseTimeTrend"
+ id: $endpointId
+ }, duration: $duration) {
+ values {
+ value
+ }
}
- getServiceThroughputTrend(serviceId: $serviceId, duration: $duration) {
- trendList
+ getEndpointThroughputTrend: getLinearIntValues(metric: {
+ name: "endpointResponseTimeTrend"
+ id: $endpointId
+ }, duration: $duration) {
+ values {
+ value
+ }
}
- getServiceSLATrend(serviceId: $serviceId, duration: $duration) {
- trendList
+ getEndpointSLATrend: getLinearIntValues(metric: {
+ name: "endpointResponseTimeTrend"
+ id: $endpointId
+ }, duration: $duration) {
+ values {
+ value
+ }
}
queryBasicTraces(condition: $traceCondition) {
traces {
@@ -50,26 +65,6 @@ const dataQuery = `
}
total
}
- getServiceTopology(serviceId: $serviceId, duration: $duration) {
- nodes {
- id
- name
- type
- ... on ServiceNode {
- sla
- calls
- numOfServiceAlarm
- }
- }
- calls {
- source
- target
- isAlert
- callType
- cpm
- avgResponseTime
- }
- }
}
`;
@@ -111,19 +106,19 @@ const spanQuery = `query Spans($traceId: ID!) {
}
}`;
-export default generateModal({
- namespace: 'service',
+export default base({
+ namespace: 'endpoint',
state: {
- getServiceResponseTimeTrend: {
- trendList: [],
+ getEndpointResponseTimeTrend: {
+ values: [],
},
- getServiceThroughputTrend: {
- trendList: [],
+ getEndpointThroughputTrend: {
+ values: [],
},
- getServiceSLATrend: {
- trendList: [],
+ getEndpointSLATrend: {
+ values: [],
},
- getServiceTopology: {
+ getEndpointTopology: {
nodes: [],
calls: [],
},
@@ -136,7 +131,7 @@ export default generateModal({
optionsQuery,
effects: {
*fetchSpans({ payload }, { call, put }) {
- const response = yield call(query, 'spans', { query: spanQuery, variables: payload.variables });
+ const response = yield call(exec, { query: spanQuery, variables: payload.variables });
yield put({
type: 'saveSpans',
payload: response,
@@ -157,21 +152,21 @@ export default generateModal({
},
};
},
- saveAppInfo(preState, { payload: allOptions }) {
+ saveServiceInfo(preState, { payload: allOptions }) {
const rawState = saveOptionsInState(null, preState, { payload: allOptions });
const { data } = rawState;
- if (data.appInfo) {
+ if (data.serviceInfo) {
return rawState;
}
const { variables: { values } } = rawState;
- if (!values.applicationId) {
+ if (!values.serviceId) {
return rawState;
}
return {
...rawState,
data: {
...data,
- appInfo: { applicationId: values.applicationId },
+ serviceInfo: { serviceId: values.serviceId },
},
};
},
@@ -189,26 +184,25 @@ export default generateModal({
subscriptions: {
setup({ history, dispatch }) {
return history.listen(({ pathname, state }) => {
- if (pathname === '/monitor/service' && state) {
- console.info(state);
+ if (pathname === '/monitor/endpoint' && state) {
dispatch({
type: 'saveVariables',
payload: {
values: {
- serviceId: state.key,
- applicationId: state.applicationId,
+ endpointId: state.key,
+ serviceId: state.serviceId,
},
labels: {
- serviceId: state.label,
- applicationId: state.applicationName,
+ endpointId: state.label,
+ serviceId: state.serviceName,
},
},
});
dispatch({
type: 'saveData',
payload: {
- appInfo: { applicationId: state.applicationId },
- serviceInfo: { key: state.key, label: state.label },
+ serviceInfo: { serviceId: state.serviceId },
+ endpointInfo: { key: state.key, label: state.label },
},
});
}
diff --git a/src/routes/Service/Service.js b/src/routes/Endpoint/Endpoint.js
similarity index 67%
rename from src/routes/Service/Service.js
rename to src/routes/Endpoint/Endpoint.js
index 62e467f..d6add80 100644
--- a/src/routes/Service/Service.js
+++ b/src/routes/Endpoint/Endpoint.js
@@ -21,9 +21,9 @@ import { connect } from 'dva';
import { Row, Col, Form, Button, Icon, Select } from 'antd';
import {
ChartCard, MiniArea, MiniBar, Sankey,
-} from '../../components/Charts';
-import { axis } from '../../utils/time';
-import { avgTimeSeries } from '../../utils/utils';
+} from 'components/Charts';
+import { axisY } from '../../utils/time';
+import { avgTS } from '../../utils/utils';
import { Panel, Search } from '../../components/Page';
import TraceList from '../../components/Trace/TraceList';
import TraceTimeline from '../Trace/TraceTimeline';
@@ -32,29 +32,29 @@ const { Item: FormItem } = Form;
const { Option } = Select;
@connect(state => ({
- service: state.service,
+ endpoint: state.endpoint,
duration: state.global.duration,
globalVariables: state.global.globalVariables,
- loading: state.loading.models.service,
+ loading: state.loading.models.endpoint,
}))
@Form.create({
mapPropsToFields(props) {
- const { variables: { values, labels } } = props.service;
+ const { variables: { values, labels } } = props.endpoint;
return {
- applicationId: Form.createFormField({
- value: { key: values.applicationId ? values.applicationId : '', label: labels.applicationId ? labels.applicationId : '' },
- }),
serviceId: Form.createFormField({
value: { key: values.serviceId ? values.serviceId : '', label: labels.serviceId ? labels.serviceId : '' },
}),
+ endpointId: Form.createFormField({
+ value: { key: values.endpointId ? values.endpointId : '', label: labels.endpointId ? labels.endpointId : '' },
+ }),
};
},
})
-export default class Service extends PureComponent {
+export default class Endpoint extends PureComponent {
componentDidMount() {
this.props.dispatch({
- type: 'service/initOptions',
- payload: { variables: this.props.globalVariables, reducer: 'saveAppInfo' },
+ type: 'endpoint/initOptions',
+ payload: { variables: this.props.globalVariables, reducer: 'saveServiceInfo' },
});
}
@@ -63,21 +63,21 @@ export default class Service extends PureComponent {
return;
}
this.props.dispatch({
- type: 'service/initOptions',
- payload: { variables: nextProps.globalVariables, reducer: 'saveAppInfo' },
+ type: 'endpoint/initOptions',
+ payload: { variables: nextProps.globalVariables, reducer: 'saveServiceInfo' },
});
}
- handleAppSelect = (selected) => {
+ handleServiceSelect = (selected) => {
this.props.dispatch({
- type: 'service/save',
+ type: 'endpoint/save',
payload: {
variables: {
- values: { applicationId: selected.key, serviceId: null },
- labels: { applicationId: selected.label, serviceId: null },
+ values: { serviceId: selected.key, endpointId: null },
+ labels: { serviceId: selected.label, endpointId: null },
},
data: {
- appInfo: { applicationId: selected.key },
+ serviceInfo: { serviceId: selected.key },
},
},
});
@@ -85,36 +85,36 @@ export default class Service extends PureComponent {
handleSelect = (selected) => {
this.props.dispatch({
- type: 'service/save',
+ type: 'endpoint/save',
payload: {
variables: {
- values: { serviceId: selected.key },
- labels: { serviceId: selected.label },
+ values: { endpointId: selected.key },
+ labels: { endpointId: selected.label },
},
data: {
- serviceInfo: selected,
+ endpointInfo: selected,
},
},
});
}
handleChange = (variables) => {
- const { variables: { values } } = this.props.service;
- if (!values.applicationId) {
+ const { variables: { values } } = this.props.endpoint;
+ if (!values.serviceId) {
return;
}
- const { key: serviceId, label: serviceName, duration } = variables;
- if (!serviceId) {
+ const { key: endpointId, label: endpointName, duration } = variables;
+ if (!endpointId) {
return;
}
this.props.dispatch({
- type: 'service/fetchData',
+ type: 'endpoint/fetchData',
payload: { variables: {
- serviceId,
+ endpointId,
duration,
traceCondition: {
- applicationId: values.applicationId,
- operationName: serviceName,
+ endpointId: parseInt(values.endpointId, 10),
+ operationName: endpointName,
queryDuration: duration,
traceState: 'ALL',
queryOrder: 'BY_DURATION',
@@ -131,30 +131,30 @@ export default class Service extends PureComponent {
handleShowTrace = (traceId) => {
const { dispatch } = this.props;
dispatch({
- type: 'service/fetchSpans',
+ type: 'endpoint/fetchSpans',
payload: { variables: { traceId } },
});
}
handleGoBack = () => {
this.props.dispatch({
- type: 'service/hideTimeline',
+ type: 'endpoint/hideTimeline',
});
}
- edgeWith = edge => edge.cpm * edge.avgResponseTime;
+ edgeWith = edge => edge.cpm;
renderPanel = () => {
- const { service, duration } = this.props;
- const { variables: { values }, data } = service;
- const { getServiceResponseTimeTrend, getServiceThroughputTrend,
- getServiceSLATrend, getServiceTopology, queryBasicTraces } = data;
- if (!values.serviceId) {
+ const { endpoint, duration } = this.props;
+ const { variables: { values }, data } = endpoint;
+ const { getEndpointResponseTimeTrend, getEndpointThroughputTrend,
+ getEndpointSLATrend, getEndpointTopology, queryBasicTraces } = data;
+ if (!values.endpointId) {
return null;
}
return (
<Panel
- variables={data.serviceInfo}
+ variables={data.endpointInfo}
globalVariables={this.props.globalVariables}
onChange={this.handleChange}
>
@@ -162,35 +162,35 @@ export default class Service extends PureComponent {
<Col xs={24} sm={24} md={24} lg={8} xl={8} style={{ marginTop: 8 }}>
<ChartCard
title="Avg Throughput"
- total={`${avgTimeSeries(getServiceThroughputTrend.trendList)} cpm`}
+ total={`${avgTS(getEndpointThroughputTrend.values)} cpm`}
contentHeight={46}
>
<MiniArea
color="#975FE4"
- data={axis(duration, getServiceThroughputTrend.trendList)}
+ data={axisY(duration, getEndpointThroughputTrend.values)}
/>
</ChartCard>
</Col>
<Col xs={24} sm={24} md={24} lg={8} xl={8} style={{ marginTop: 8 }}>
<ChartCard
title="Avg Response Time"
- total={`${avgTimeSeries(getServiceResponseTimeTrend.trendList)} ms`}
+ total={`${avgTS(getEndpointResponseTimeTrend.values)} ms`}
contentHeight={46}
>
<MiniArea
- data={axis(duration, getServiceResponseTimeTrend.trendList)}
+ data={axisY(duration, getEndpointResponseTimeTrend.values)}
/>
</ChartCard>
</Col>
<Col xs={24} sm={24} md={24} lg={8} xl={8} style={{ marginTop: 8 }}>
<ChartCard
title="Avg SLA"
- total={`${(avgTimeSeries(getServiceSLATrend.trendList) / 100).toFixed(2)} %`}
+ total={`${(avgTS(getEndpointSLATrend.values) / 100).toFixed(2)} %`}
>
<MiniBar
animate={false}
height={46}
- data={axis(duration, getServiceSLATrend.trendList,
+ data={axisY(duration, getEndpointSLATrend.values,
({ x, y }) => ({ x, y: y / 100 }))}
/>
</ChartCard>
@@ -209,7 +209,7 @@ export default class Service extends PureComponent {
</ChartCard>
</Col>
</Row>
- {this.renderSankey(getServiceTopology)}
+ {this.renderSankey(getEndpointTopology)}
</Panel>
);
}
@@ -238,13 +238,13 @@ export default class Service extends PureComponent {
>
<Sankey
data={nData}
- edgeTooltip={['target*source*cpm*avgResponseTime*isAlert', (target, source, cpm, avgResponseTime) => {
+ edgeTooltip={['target*source*cpm', (target, source, cpm) => {
return {
name: `${source.name} to ${target.name} </span>`,
- value: `${cpm < 1 ? '<1' : cpm} cpm ${avgResponseTime}ms`,
+ value: `${cpm} cpm`,
};
}]}
- edgeColor={['isAlert', isAlert => (isAlert ? '#DC143C' : '#bbb')]}
+ edgeColor="#bbb"
/>
</ChartCard>
</Col>
@@ -252,9 +252,9 @@ export default class Service extends PureComponent {
}
render() {
- const { form, service } = this.props;
+ const { form, endpoint } = this.props;
const { getFieldDecorator } = form;
- const { variables: { options }, data } = service;
+ const { variables: { options }, data } = endpoint;
const { showTimeline, queryTrace, currentTraceId } = data;
return (
<div>
@@ -271,31 +271,31 @@ export default class Service extends PureComponent {
<Col span={showTimeline ? 0 : 24}>
<Form layout="inline">
<FormItem>
- {getFieldDecorator('applicationId')(
+ {getFieldDecorator('serviceId')(
<Select
showSearch
optionFilterProp="children"
style={{ width: 200 }}
- placeholder="Select a application"
+ placeholder="Select a service"
labelInValue
- onSelect={this.handleAppSelect.bind(this)}
+ onSelect={this.handleServiceSelect.bind(this)}
>
- {options.applicationId && options.applicationId.map(app =>
- <Option key={app.key} value={app.key}>{app.label}</Option>)}
+ {options.serviceId && options.serviceId.map(service =>
+ <Option key={service.key} value={service.key}>{service.label}</Option>)}
</Select>
)}
</FormItem>
- {data.appInfo ? (
+ {data.serviceInfo ? (
<FormItem>
- {getFieldDecorator('serviceId')(
+ {getFieldDecorator('endpointId')(
<Search
- placeholder="Search a service"
+ placeholder="Search a endpoint"
onSelect={this.handleSelect.bind(this)}
- url="/service/search"
- variables={data.appInfo}
+ url="/graphql"
+ variables={data.serviceInfo}
query={`
- query SearchService($applicationId: ID!, $keyword: String!) {
- searchService(applicationId: $applicationId, keyword: $keyword, topN: 10) {
+ query SearchEndpoint($serviceId: ID!, $keyword: String!) {
+ searchEndpoint(serviceId: $serviceId, keyword: $keyword, limit: 10) {
key: id
label: name
}
diff --git a/src/utils/time.js b/src/utils/time.js
index e2476ca..b4e7301 100644
--- a/src/utils/time.js
+++ b/src/utils/time.js
@@ -22,6 +22,11 @@ export function axis({ display }, data, tranformFunc) {
(tranformFunc ? tranformFunc({ x: v, y: data[i] }) : { x: v, y: data[i] }));
}
+export function axisY({ display }, data, tranformFunc) {
+ return display.range.map((v, i) =>
+ (tranformFunc ? tranformFunc({ x: v, y: data[i] ? data[i].value : null }) : { x: v, y: data[i] ? data[i].value : null }));
+}
+
export function generateDuration({ from, to }) {
const start = from();
const end = to();
diff --git a/src/utils/utils.js b/src/utils/utils.js
index 2969ebf..d6c4e3b 100644
--- a/src/utils/utils.js
+++ b/src/utils/utils.js
@@ -27,6 +27,13 @@ export function avgTimeSeries(list) {
(acc, curr) => acc + curr) / filteredList.length).toFixed(2)) : 0;
}
+export function avgTS(list) {
+ const filteredList = list.map(_ => _.value).filter(_ => _ > 0);
+ return filteredList.length > 0 ?
+ parseFloat((filteredList.reduce(
+ (acc, curr) => acc + curr) / filteredList.length).toFixed(2)) : 0;
+}
+
export function getPlainNode(nodeList, parentPath = '') {
const arr = [];
nodeList.forEach((node) => {