You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2019/02/22 16:06:13 UTC

[incubator-skywalking-ui] branch master updated: Feature: Add serviceInstance Search Support (#233)

This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-skywalking-ui.git


The following commit(s) were added to refs/heads/master by this push:
     new 8b5e69c  Feature: Add serviceInstance Search Support (#233)
8b5e69c is described below

commit 8b5e69c4513ff352dcaf6346b024dc781e2c2d8c
Author: Allen Wang <Al...@outlook.com>
AuthorDate: Sat Feb 23 00:06:09 2019 +0800

    Feature: Add serviceInstance Search Support (#233)
---
 .roadhogrc.mock.js              |  2 +-
 mock/trace.js                   |  7 ++++
 src/models/trace.js             | 27 ++++++++++++
 src/routes/Trace/TraceSearch.js | 92 +++++++++++++++++++++++++++++++++++------
 4 files changed, 114 insertions(+), 14 deletions(-)

diff --git a/.roadhogrc.mock.js b/.roadhogrc.mock.js
index 1de7bd0..e59d3b2 100644
--- a/.roadhogrc.mock.js
+++ b/.roadhogrc.mock.js
@@ -33,7 +33,7 @@ const schema = makeExecutableSchema({ typeDefs: [
   "scalar Long",
   fs.readFileSync('query-protocol/common.graphqls', 'utf8'),
   fs.readFileSync('query-protocol/metadata.graphqls', 'utf8'),
-  fs.readFileSync('query-protocol/database.graphqls', 'utf8'),
+  fs.readFileSync('query-protocol/top-n-records.graphqls', 'utf8'),
   fs.readFileSync('query-protocol/alarm.graphqls', 'utf8'),
   fs.readFileSync('query-protocol/metric.graphqls', 'utf8'),
   fs.readFileSync('query-protocol/aggregation.graphqls', 'utf8'),
diff --git a/mock/trace.js b/mock/trace.js
index 93867b0..bdd79e4 100644
--- a/mock/trace.js
+++ b/mock/trace.js
@@ -19,6 +19,13 @@
 import mockjs from 'mockjs';
 
 export default {
+  
+  getServiceInstances: () => {
+    const data = mockjs.mock({
+      'instanceId|20-50': [{ 'id|+1': 3, name: function() { return `service-${this.id}`; } }], // eslint-disable-line
+    });
+    return data.instanceId;
+  },
   TraceBrief: () => {
     let offset = 0;
     return mockjs.mock({
diff --git a/src/models/trace.js b/src/models/trace.js
index 9b2f8c4..bb2485d 100644
--- a/src/models/trace.js
+++ b/src/models/trace.js
@@ -29,6 +29,15 @@ const optionsQuery = `
   }
 `;
 
+const serviceInstanceQuery = `
+  query ServiceInstanceOption($duration: Duration!, $serviceId: ID!) {
+    instanceId: getServiceInstances(duration: $duration, serviceId: $serviceId) {
+      key: id
+      label: name
+    }
+  }
+`;
+
 const dataQuery = `
   query BasicTraces($condition: TraceQueryCondition) {
     queryBasicTraces(condition: $condition) {
@@ -85,6 +94,7 @@ const spanQuery = `query Spans($traceId: ID!) {
 export default base({
   namespace: 'trace',
   state: {
+    instances: [],
     queryBasicTraces: {
       traces: [],
       total: 0,
@@ -116,6 +126,13 @@ export default base({
   },
   dataQuery,
   effects: {
+    *fetchInstances({ payload }, { call, put }) {
+      const response = yield call(exec, { query: serviceInstanceQuery, variables: payload.variables });
+      yield put({
+        type: 'saveInstances',
+        payload: response,
+      });
+    },
     *fetchSpans({ payload }, { call, put }) {
       const response = yield call(exec, { query: spanQuery, variables: payload.variables });
       yield put({
@@ -138,6 +155,16 @@ export default base({
         },
       };
     },
+    saveInstances(state, { payload }) {
+      const { data } = state;
+      return {
+        ...state,
+        data: {
+          ...data,
+          instances: payload.data.instanceId,
+        },
+      };
+    },
     hideTimeline(state) {
       const { data } = state;
       return {
diff --git a/src/routes/Trace/TraceSearch.js b/src/routes/Trace/TraceSearch.js
index 5b40633..4448304 100644
--- a/src/routes/Trace/TraceSearch.js
+++ b/src/routes/Trace/TraceSearch.js
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-import React, { PureComponent } from 'react';
+import React, { Component } from 'react';
 import { Form, Input, Select, Button, Card, InputNumber, Row, Col, Pagination, DatePicker,notification } from 'antd';
 import { Chart, Geom, Axis, Tooltip, Legend } from 'bizcharts';
 import { DataSet } from '@antv/data-set';
@@ -51,7 +51,15 @@ const initPaging = {
     return result;
   },
 })
-export default class Trace extends PureComponent {
+export default class Trace extends Component {
+  constructor(props){
+    super(props);
+    this.state = {
+      serviceId: '',
+      serviceInstanceId: '',
+    }
+  }
+
   componentDidMount() {
     this.timer = false;
     const {...propsData} = this.props;
@@ -118,12 +126,20 @@ export default class Trace extends PureComponent {
 
   fetchData = (queryCondition, paging = initPaging) => {
     const {...propsData} = this.props;
+    const { serviceId, serviceInstanceId } = this.state;
+    const newData = {...queryCondition, serviceId, serviceInstanceId}
+    if (!serviceId) {
+      delete newData.serviceId;
+    }
+    if (!serviceInstanceId) {
+      delete newData.serviceInstanceId;
+    }
     propsData.dispatch({
       type: 'trace/fetchData',
       payload: {
         variables: {
           condition: {
-            ...queryCondition,
+            ...newData,
             paging,
           },
         },
@@ -161,6 +177,42 @@ export default class Trace extends PureComponent {
     });
   }
 
+  handleSelectInstance = (serviceInstanceId) => {
+    this.setState({ serviceInstanceId });
+  }
+  
+  handleRefreshServiceInstances = () => {
+    const { dispatch } = this.props;
+    const { ...propsData } = this.props;
+    const { serviceId } = this.state;
+    propsData.form.validateFields((err, fieldsValue) => {
+      if (err || !serviceId) return;
+      const rangeTime = fieldsValue['range-time-picker'];
+      const duration = generateDuration({ from: () => rangeTime[0], to: () => rangeTime[1] }).input;
+      dispatch({
+        type: 'trace/fetchInstances',
+        payload: { variables: { duration, serviceId } },
+      });
+    });
+    return true;
+  }
+  
+  handleShowServiceInstances = (serviceId) => {
+    const { dispatch } = this.props;
+    const { ...propsData } = this.props;
+    this.setState({ serviceId });
+    propsData.form.validateFields((err, fieldsValue) => {
+      if (err || !serviceId) return;
+      const rangeTime = fieldsValue['range-time-picker'];
+      const duration = generateDuration({ from: () => rangeTime[0], to: () => rangeTime[1] }).input;
+      dispatch({
+        type: 'trace/fetchInstances',
+        payload: { variables: { duration, serviceId } },
+      });
+    });
+    return true;
+  }
+
   renderPointChart = (traces) => {
     if (!traces) {
       return null;
@@ -240,6 +292,7 @@ export default class Trace extends PureComponent {
             }],
           })(
             <RangePicker
+              onCalendarChange={this.handleRefreshServiceInstances} 
               showTime
               disabledDate={current => current && current.valueOf() >= Date.now()}
               format="YYYY-MM-DD HH:mm"
@@ -248,16 +301,29 @@ export default class Trace extends PureComponent {
           )}
         </FormItem>
         <FormItem label="Service">
-          {getFieldDecorator('serviceId')(
-            <Select placeholder="All service" style={{ width: '100%' }}>
-              {options.serviceId && options.serviceId.map((service) => {
-                  return (
-                    <Option key={service.key ? service.key : -1} value={service.key}>
-                      {service.label}
-                    </Option>);
-                })}
-            </Select>
-          )}
+          <Select placeholder="All services" onChange={this.handleShowServiceInstances} style={{ width: '100%' }}>
+            {options.serviceId && options.serviceId.map((service) => {
+               if (service.key) {
+                return (
+                  <Option key={service.key ? service.key : -1} value={service.key? service.key : ''}>
+                    {service.label}
+                  </Option>);
+               }
+                return (
+                  <Option value="">All Services</Option>
+            )})}
+          </Select>
+        </FormItem>
+        <FormItem label="ServiceInstance">
+          <Select placeholder="All Service Instances" onChange={this.handleSelectInstance} style={{ width: '100%' }}>
+            <Option value="">All Service Instances</Option>
+            {propsData.trace.data.instances && propsData.trace.data.instances.map((instance) => {
+                return (
+                  <Option key={instance.key ? instance.key : -1} value={instance.key}>
+                    {instance.label}
+                  </Option>);
+              })}
+          </Select>
         </FormItem>
         <FormItem label="Trace State">
           {getFieldDecorator('traceState')(