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

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


The following commit(s) were added to refs/heads/master by this push:
     new 70ad10c  Feat: implement viewing logs on trace page (#420)
70ad10c is described below

commit 70ad10c08e7eb7d877e33e993296775609839de4
Author: Qiuxia Fan <[email protected]>
AuthorDate: Wed Jan 27 15:55:08 2021 +0800

    Feat: implement viewing logs on trace page (#420)
    
    * feat: add sidebox
    
    * feat: implement trace logs
    
    * feat: implement turning page
    
    * fix: update span logs
    
    * feat: query trace logs
    
    * fix: type
    
    * fix: logs
    
    * fix: type
    
    * feat: update view logs
    
    * fix: update sidebox
    
    * fix:typo
---
 src/assets/lang/en.ts                              |   2 +
 src/assets/lang/zh.ts                              |   2 +
 src/store/modules/trace/index.ts                   |  25 ++++
 src/store/mutation-types.ts                        |   4 +
 .../components/common/trace-detail-chart-table.vue |  59 +-------
 src/views/components/log/log-service-detail.vue    |  16 +--
 .../components/log/log-table/log-service-item.vue  |   6 +-
 src/views/components/log/log-table/log-table.vue   |   5 +-
 .../components/trace/trace-detail-chart-list.vue   |  89 ++----------
 .../components/trace/trace-detail-chart-tree.vue   |  58 +-------
 src/views/components/trace/trace-detail.vue        |  54 +++++++-
 src/views/components/trace/trace-search.vue        |  27 +++-
 src/views/components/trace/trace-span-logs.vue     | 152 +++++++++++++++++++++
 src/views/components/trace/trace-table.vue         |   5 +-
 14 files changed, 290 insertions(+), 214 deletions(-)

diff --git a/src/assets/lang/en.ts b/src/assets/lang/en.ts
index c7201e5..b9df4b0 100644
--- a/src/assets/lang/en.ts
+++ b/src/assets/lang/en.ts
@@ -186,6 +186,7 @@ const m = {
   errorPage: 'Error Page',
   category: 'Category',
   grade: 'Grade',
+  relatedTraceLogs: 'Related Logs',
   setConditions: 'More Conditions',
   metricName: 'Metric Name',
   keywordsOfContent: 'Keys Of Content',
@@ -194,6 +195,7 @@ const m = {
   isError: 'Error',
   contentType: 'Content Type',
   content: 'Content',
+  viewLogs: 'View Logs',
 };
 
 export default m;
diff --git a/src/assets/lang/zh.ts b/src/assets/lang/zh.ts
index e696d0f..b0b74bd 100644
--- a/src/assets/lang/zh.ts
+++ b/src/assets/lang/zh.ts
@@ -185,6 +185,7 @@ const m = {
   errorPage: '错误页面',
   category: '类别',
   grade: '等级',
+  relatedTraceLogs: '相关的日志',
   setConditions: '更多条件',
   metricName: '指标名称',
   keywordsOfContent: '内容关键词',
@@ -193,6 +194,7 @@ const m = {
   isError: '错误',
   contentType: '内容类型',
   content: '内容',
+  viewLogs: '查看日志',
 };
 
 export default m;
diff --git a/src/store/modules/trace/index.ts b/src/store/modules/trace/index.ts
index a3feb8d..3583dc8 100644
--- a/src/store/modules/trace/index.ts
+++ b/src/store/modules/trace/index.ts
@@ -30,6 +30,8 @@ export interface State {
   traceTotal: number;
   traceSpans: Span[];
   currentTrace: Trace;
+  traceSpanLogs: any[];
+  traceSpanLogsTotal: number;
 }
 
 const initState: State = {
@@ -50,6 +52,8 @@ const initState: State = {
     start: '',
     traceIds: [],
   },
+  traceSpanLogs: [],
+  traceSpanLogsTotal: 0,
 };
 
 // mutations
@@ -104,6 +108,12 @@ const mutations: MutationTree<State> = {
       traceIds: [],
     };
   },
+  [types.SET_TRACE_SPAN_LOGS](state: State, logs: any[]) {
+    state.traceSpanLogs = logs;
+  },
+  [types.SET_TRACE_SPAN_LOGS_TOTAL](state: State, data: number) {
+    state.traceSpanLogsTotal = data;
+  },
 };
 
 // actions
@@ -149,6 +159,21 @@ const actions: ActionTree<State, any> = {
         context.commit(types.SET_TRACE_SPANS, res.data.data.trace.spans);
       });
   },
+  GET_TRACE_SPAN_LOGS(context: { commit: Commit }, params: any) {
+    return graph
+      .query('queryServiceLogs')
+      .params(params)
+      .then((res: AxiosResponse<any>) => {
+        if (res.data && res.data.errors) {
+          context.commit('SET_TRACE_SPAN_LOGS', []);
+          context.commit('SET_TRACE_SPAN_LOGS_TOTAL', 0);
+
+          return;
+        }
+        context.commit('SET_TRACE_SPAN_LOGS', res.data.data.queryLogs.logs);
+        context.commit('SET_TRACE_SPAN_LOGS_TOTAL', 
res.data.data.queryLogs.total);
+      });
+  },
 };
 
 export default {
diff --git a/src/store/mutation-types.ts b/src/store/mutation-types.ts
index 6846c00..3957d83 100644
--- a/src/store/mutation-types.ts
+++ b/src/store/mutation-types.ts
@@ -68,6 +68,10 @@ export const SET_CURRENT_TRACE = 'SET_CURRENT_TRACE';
 export const SET_TRACE_FORM = 'SET_TRACE_FORM';
 export const SET_TRACE_FORM_ITEM = 'SET_TRACE_FORM_ITEM';
 export const SET_DEFAULT_EMPTY_TRACE = 'SET_DEFAULT_EMPTY_TRACE';
+export const SET_TRACE_LOGS = 'SET_TRACE_LOGS';
+export const SET_TRACE_LOGS_TOTAL = 'SET_TRACE_LOGS_TOTAL';
+export const SET_TRACE_SPAN_LOGS_TOTAL = 'SET_TRACE_SPAN_LOGS_TOTAL';
+export const SET_TRACE_SPAN_LOGS = 'SET_TRACE_SPAN_LOGS';
 
 // topo
 export const SET_TOPO = 'SET_TOPO';
diff --git a/src/views/components/common/trace-detail-chart-table.vue 
b/src/views/components/common/trace-detail-chart-table.vue
index 52c8048..3776c49 100644
--- a/src/views/components/common/trace-detail-chart-table.vue
+++ b/src/views/components/common/trace-detail-chart-table.vue
@@ -23,62 +23,7 @@ limitations under the License. -->
       <div class="trace-tips" v-if="!tableData.length">{{ $t('noData') }}</div>
     </TraceContainer>
     <rk-sidebox :width="'50%'" :show.sync="showDetail" :title="$t('spanInfo')">
-      <div class="rk-trace-detail">
-        <h5 class="mb-15">{{ $t('tags') }}.</h5>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">{{ $t('service') }}:</span
-          ><span class="g-sm-8 wba">{{ this.currentSpan.serviceCode }}</span>
-        </div>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">{{ $t('endpoint') }}:</span
-          ><span class="g-sm-8 wba">{{ this.currentSpan.label }}</span>
-        </div>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">{{ $t('spanType') }}:</span
-          ><span class="g-sm-8 wba">{{ this.currentSpan.type }}</span>
-        </div>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">{{ $t('component') }}:</span
-          ><span class="g-sm-8 wba">{{ this.currentSpan.component }}</span>
-        </div>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">Peer:</span><span class="g-sm-8 wba">{{ 
this.currentSpan.peer || 'No Peer' }}</span>
-        </div>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">{{ $t('error') }}:</span
-          ><span class="g-sm-8 wba">{{ this.currentSpan.isError }}</span>
-        </div>
-        <div class="mb-10 clear" v-for="i in this.currentSpan.tags" 
:key="i.key">
-          <span class="g-sm-4 grey">{{ i.key }}:</span>
-          <span class="g-sm-8 wba">
-            {{ i.value }}
-            <svg v-if="i.key === 'db.statement'" class="icon vm grey 
link-hover cp ml-5" @click="copy(i.value)">
-              <use xlink:href="#review-list"></use>
-            </svg>
-          </span>
-        </div>
-        <h5 class="mb-10" v-if="this.currentSpan.logs" 
v-show="this.currentSpan.logs.length">{{ $t('logs') }}.</h5>
-        <div v-for="(i, index) in this.currentSpan.logs" :key="index">
-          <div class="mb-10 sm">
-            <span class="mr-10">{{ $t('time') }}:</span>
-            <span class="grey">{{ i.time | dateformat }}</span>
-          </div>
-          <div class="mb-15 clear" v-for="(_i, _index) in i.data" 
:key="_index">
-            <div class="mb-10">
-              {{ _i.key }}:<span
-                v-if="_i.key === 'stack'"
-                class="r rk-sidebox-magnify"
-                @click="showCurrentSpanDetail(_i.key, _i.value)"
-              >
-                <svg class="icon">
-                  <use xlink:href="#magnify"></use>
-                </svg>
-              </span>
-            </div>
-            <pre class="pl-15 mt-0 mb-0 sm oa">{{ _i.value }}</pre>
-          </div>
-        </div>
-      </div>
+      <TraceSpanLogs :currentSpan="currentSpan" />
     </rk-sidebox>
   </div>
 </template>
@@ -97,11 +42,13 @@ limitations under the License. -->
   import copy from '@/utils/copy';
   import TraceContainer from './trace-chart-table/trace-container';
   import _ from 'lodash';
+  import TraceSpanLogs from '../trace/trace-span-logs.vue';
   /* eslint-disable */
   /* tslint:disable */
   export default {
     components: {
       TraceContainer,
+      TraceSpanLogs,
     },
     props: ['data', 'traceId', 'showBtnDetail', 'HeaderType'],
     watch: {
diff --git a/src/views/components/log/log-service-detail.vue 
b/src/views/components/log/log-service-detail.vue
index f16c944..6a6a7b1 100644
--- a/src/views/components/log/log-service-detail.vue
+++ b/src/views/components/log/log-service-detail.vue
@@ -19,7 +19,7 @@ limitations under the License. -->
         <use xlink:href="#spinner"></use>
       </svg>
     </div>
-    <LogTable :tableData="data" :type="`service`">
+    <LogTable :tableData="data" :type="`service`" :noLink="noLink">
       <div class="log-tips" v-if="!data.length">{{ $t('noData') }}</div>
     </LogTable>
     <rk-sidebox :width="'800px'" :show.sync="showDetail" 
:title="$t('logDetail')">
@@ -51,24 +51,24 @@ limitations under the License. -->
     components: { LogTable },
   })
   export default class LogServiceDetail extends Vue {
-    @State('rocketLog') private logState: any;
     @Prop() private data: any;
     @Prop() private loading!: true;
     @Prop() private showBtnDetail: any;
+    @Prop() private noLink!: boolean;
 
     private columns = ServiceLogDetail;
-    private showDetail = false;
+    private showDetail: boolean = false;
     private list = [];
     private currentLog: any = {};
-    private logContent: any = '';
-    private logTags: any = '';
-    private formatJson = formatJson;
+    private logContent: string = '';
+    private logTags: string = '';
+
     private created() {
       this.$eventBus.$on('HANDLE-SELECT-LOG', this, this.handleSelectLog);
     }
-    private handleSelectLog(data: any) {
+    private handleSelectLog(data: any[]) {
       this.currentLog = data;
-      this.logTags = this.currentLog.tags.map((d: any) => {
+      this.logTags = this.currentLog.tags.map((d: { key: string; value: string 
}) => {
         return `${d.key} = ${d.value}`;
       });
       if (this.currentLog.contentType === 'JSON') {
diff --git a/src/views/components/log/log-table/log-service-item.vue 
b/src/views/components/log/log-table/log-service-item.vue
index a24f63f..278d00d 100644
--- a/src/views/components/log/log-table/log-service-item.vue
+++ b/src/views/components/log/log-table/log-service-item.vue
@@ -19,7 +19,10 @@ limitations under the License. -->
       <span v-if="item.label === 'timestamp'">
         {{ data.time | dateformat }}
       </span>
-      <router-link v-if="item.label === 'traceId'" :to="{ name: 'trace', 
query: { traceid: data[item.label] } }">
+      <router-link
+        v-if="item.label === 'traceId' && !noLink"
+        :to="{ name: 'trace', query: { traceid: data[item.label] } }"
+      >
         <span>{{ data[item.label] }}</span>
       </router-link>
       <span v-else>{{ data[item.label] }}</span>
@@ -33,6 +36,7 @@ limitations under the License. -->
   @Component
   export default class ServiceItem extends Vue {
     @Prop() private data: any;
+    @Prop() private noLink!: any;
     private columns = ServiceLogConstants;
     private showSelectSpan() {
       this.$eventBus.$emit('HANDLE-SELECT-LOG', this.data);
diff --git a/src/views/components/log/log-table/log-table.vue 
b/src/views/components/log/log-table/log-table.vue
index 8795e88..9708650 100644
--- a/src/views/components/log/log-table/log-table.vue
+++ b/src/views/components/log/log-table/log-table.vue
@@ -32,7 +32,8 @@ limitations under the License. -->
       <BrowserItem :method="method" v-for="(item, index) in tableData" 
:data="item" :key="'key' + index" />
     </div>
     <div v-else>
-      <ServiceItem v-for="(item, index) in tableData" :data="item" :key="'key' 
+ index" />
+      "
+      <ServiceItem v-for="(item, index) in tableData" :data="item" :key="'key' 
+ index" :noLink="noLink" />
     </div>
     <slot></slot>
   </div>
@@ -45,7 +46,7 @@ limitations under the License. -->
   export default {
     components: { ServiceItem, BrowserItem },
     name: 'LogContainer',
-    props: ['type', 'tableData'],
+    props: ['type', 'tableData', 'noLink'],
     data() {
       return {
         method: 380,
diff --git a/src/views/components/trace/trace-detail-chart-list.vue 
b/src/views/components/trace/trace-detail-chart-list.vue
index 286f4b3..d540cd3 100644
--- a/src/views/components/trace/trace-detail-chart-list.vue
+++ b/src/views/components/trace/trace-detail-chart-list.vue
@@ -29,61 +29,7 @@ limitations under the License. -->
     </transition-group>
     <a class="rk-btn r vm  tc" @click="downloadTrace">{{ $t('exportImage') 
}}</a>
     <rk-sidebox :width="'50%'" :show.sync="showDetail" :title="$t('spanInfo')">
-      <div class="rk-trace-detail">
-        <h5 class="mb-15">{{ $t('tags') }}.</h5>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">{{ $t('service') }}:</span
-          ><span class="g-sm-8 wba">{{ this.currentSpan.serviceCode }}</span>
-        </div>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">{{ $t('endpoint') }}:</span
-          ><span class="g-sm-8 wba">{{ this.currentSpan.label }}</span>
-        </div>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">{{ $t('spanType') }}:</span
-          ><span class="g-sm-8 wba">{{ this.currentSpan.type }}</span>
-        </div>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">{{ $t('component') }}:</span
-          ><span class="g-sm-8 wba">{{ this.currentSpan.component }}</span>
-        </div>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">Peer:</span><span class="g-sm-8 wba">{{ 
this.currentSpan.peer || 'No Peer' }}</span>
-        </div>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">{{ $t('error') }}:</span
-          ><span class="g-sm-8 wba">{{ this.currentSpan.isError }}</span>
-        </div>
-        <div class="mb-10 clear" v-for="i in this.currentSpan.tags" 
:key="i.key">
-          <span class="g-sm-4 grey">{{ i.key }}:</span>
-          <span class="g-sm-8 wba">
-            {{ i.value }}
-            <svg v-if="i.key === 'db.statement'" class="icon vm grey 
link-hover cp ml-5" @click="copy(i.value)">
-              <use xlink:href="#review-list"></use>
-            </svg>
-          </span>
-        </div>
-        <h5 class="mb-10" v-if="this.currentSpan.logs" 
v-show="this.currentSpan.logs.length">{{ $t('logs') }}.</h5>
-        <div v-for="(i, index) in this.currentSpan.logs" :key="index">
-          <div class="mb-10 sm">
-            <span class="mr-10">{{ $t('time') }}:</span><span class="grey">{{ 
i.time | dateformat }}</span>
-          </div>
-          <div class="mb-15 clear" v-for="(_i, _index) in i.data" 
:key="_index">
-            <div class="mb-10">
-              {{ _i.key }}:<span
-                v-if="_i.key === 'stack'"
-                class="r rk-sidebox-magnify"
-                @click="showCurrentSpanDetail(_i.key, _i.value)"
-              >
-                <svg class="icon">
-                  <use xlink:href="#magnify"></use>
-                </svg>
-              </span>
-            </div>
-            <pre class="pl-15 mt-0 mb-0 sm oa">{{ _i.value }}</pre>
-          </div>
-        </div>
-      </div>
+      <TraceSpanLogs :currentSpan="currentSpan" />
     </rk-sidebox>
     <div class="trace-list">
       <div ref="traceList"></div>
@@ -95,7 +41,9 @@ limitations under the License. -->
   import * as d3 from 'd3';
   import Trace from './d3-trace';
   import _ from 'lodash';
+  import TraceSpanLogs from './trace-span-logs.vue';
   export default {
+    components: {TraceSpanLogs},
     props: ['data', 'traceId'],
     data() {
       return {
@@ -105,6 +53,7 @@ limitations under the License. -->
         currentSpan: [],
         loading: true,
         fixSpansSize: 0,
+        showRelatedLogs: false,
       };
     },
     watch: {
@@ -134,7 +83,6 @@ limitations under the License. -->
       // this.computedScale();
     },
     methods: {
-      copy,
       handleSelectSpan(i) {
         this.currentSpan = i.data;
         this.showDetail = true;
@@ -323,27 +271,6 @@ limitations under the License. -->
           d.children.forEach((i) => this.collapse(i));
         }
       },
-      showCurrentSpanDetail(title, text) {
-        const textLineNumber = text.split('\n').length;
-        let textHeight = textLineNumber * 20.2 + 10;
-        const tmpHeight = window.innerHeight * 0.9;
-        textHeight = textHeight >= tmpHeight ? tmpHeight : textHeight;
-        this.$modal.show('dialog', {
-          title,
-          text: `<div style="height:${textHeight}px">${text}</div>`,
-          buttons: [
-            {
-              title: 'Copy',
-              handler: () => {
-                this.copy(text);
-              },
-            },
-            {
-              title: 'Close',
-            },
-          ],
-        });
-      },
       downloadTrace() {
         const serializer = new XMLSerializer();
         const svgNode = d3.select('.trace-list-dowanload').node();
@@ -413,4 +340,12 @@ limitations under the License. -->
     overflow: auto;
     font-family: monospace;
   }
+  .rk-popup-btn {
+    color: #fff;
+    padding: 10px 9px;
+    border-radius: 4px;
+    margin-top: 40px;
+    width: 100%;
+    text-align: center;
+  }
 </style>
diff --git a/src/views/components/trace/trace-detail-chart-tree.vue 
b/src/views/components/trace/trace-detail-chart-tree.vue
index 8f0601c..0659d7e 100644
--- a/src/views/components/trace/trace-detail-chart-tree.vue
+++ b/src/views/components/trace/trace-detail-chart-tree.vue
@@ -28,61 +28,7 @@ limitations under the License. -->
       <a class="trace-tree-btn mr-10" @click="tree.getTopChild()">Top 5 of 
children</a>
     </div>
     <rk-sidebox :width="'50%'" :show.sync="showDetail" :title="$t('spanInfo')">
-      <div class="rk-trace-detail">
-        <h5 class="mb-15">{{ $t('tags') }}.</h5>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">{{ $t('service') }}:</span
-          ><span class="g-sm-8 wba">{{ this.currentSpan.serviceCode }}</span>
-        </div>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">{{ $t('endpoint') }}:</span
-          ><span class="g-sm-8 wba">{{ this.currentSpan.label }}</span>
-        </div>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">{{ $t('spanType') }}:</span
-          ><span class="g-sm-8 wba">{{ this.currentSpan.type }}</span>
-        </div>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">{{ $t('component') }}:</span
-          ><span class="g-sm-8 wba">{{ this.currentSpan.component }}</span>
-        </div>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">Peer:</span><span class="g-sm-8 wba">{{ 
this.currentSpan.peer || 'No Peer' }}</span>
-        </div>
-        <div class="mb-10 clear">
-          <span class="g-sm-4 grey">{{ $t('error') }}:</span
-          ><span class="g-sm-8 wba">{{ this.currentSpan.isError }}</span>
-        </div>
-        <div class="mb-10 clear" v-for="i in this.currentSpan.tags" 
:key="i.key">
-          <span class="g-sm-4 grey">{{ i.key }}:</span>
-          <span class="g-sm-8 wba">
-            {{ i.value }}
-            <svg v-if="i.key === 'db.statement'" class="icon vm grey 
link-hover cp ml-5" @click="copy(i.value)">
-              <use xlink:href="#review-list"></use>
-            </svg>
-          </span>
-        </div>
-        <h5 class="mb-10" v-if="this.currentSpan.logs" 
v-show="this.currentSpan.logs.length">{{ $t('logs') }}.</h5>
-        <div v-for="(i, index) in this.currentSpan.logs" :key="index">
-          <div class="mb-10 sm">
-            <span class="mr-10">{{ $t('time') }}:</span><span class="grey">{{ 
i.time | dateformat }}</span>
-          </div>
-          <div class="mb-15 clear" v-for="(_i, _index) in i.data" 
:key="_index">
-            <div class="mb-10">
-              {{ _i.key }}:<span
-                v-if="_i.key === 'stack'"
-                class="r rk-sidebox-magnify"
-                @click="showCurrentSpanDetail(_i.key, _i.value)"
-              >
-                <svg class="icon">
-                  <use xlink:href="#magnify"></use>
-                </svg>
-              </span>
-            </div>
-            <pre class="pl-15 mt-0 mb-0 sm oa">{{ _i.value }}</pre>
-          </div>
-        </div>
-      </div>
+      <TraceSpanLogs :currentSpan="currentSpan" />
     </rk-sidebox>
     <div class="trace-tree" style="height:100%">
       <div class="trace-tree-inner" ref="traceTree"></div>
@@ -94,9 +40,11 @@ limitations under the License. -->
   import * as d3 from 'd3';
   import Tree from './d3-trace-tree';
   import _ from 'lodash';
+  import TraceSpanLogs from './trace-span-logs.vue';
   /* eslint-disable */
   /* tslint:disable */
   export default {
+    components: {TraceSpanLogs},
     props: ['data', 'traceId'],
     data(){
       return {
diff --git a/src/views/components/trace/trace-detail.vue 
b/src/views/components/trace/trace-detail.vue
index 496aaff..bda492e 100644
--- a/src/views/components/trace/trace-detail.vue
+++ b/src/views/components/trace/trace-detail.vue
@@ -14,15 +14,25 @@ See the License for the specific language governing 
permissions and
 limitations under the License. -->
 <template>
   <div class="rk-trace-detail flex-v">
+    <rk-sidebox class="rk-log-box" :width="'100%'" :show.sync="showTraceLogs" 
:title="$t('relatedTraceLogs')">
+      <RkPage
+        :currentSize="pageSize"
+        :currentPage="pageNum"
+        @changePage="turnLogsPage"
+        :total="rocketTrace.traceLogsTotal"
+      />
+      <LogTable :tableData="rocketTrace.traceSpanLogs || []" :type="`service`" 
:noLink="true">
+        <div class="log-tips" v-if="!rocketTrace.traceSpanLogs.length">{{ 
$t('noData') }}</div>
+      </LogTable>
+    </rk-sidebox>
     <div class="rk-trace-detail-wrapper clear" v-if="current.endpointNames">
       <h5 class="mb-5 mt-0">
-        <svg v-if="current.isError" class="icon red vm mr-5 sm">
-          <use xlink:href="#clear"></use>
-        </svg>
+        <rk-icon icon="clear" v-if="current.isError" class="red mr-5 sm" />
         <span class="vm">{{ current.endpointNames[0] }}</span>
+        <div class="rk-trace-log-btn bg-blue r mr-10" 
@click="searchTraceLogs">{{ $t('viewLogs') }}</div>
       </h5>
       <div class="mb-5 blue sm">
-        <select class="rk-trace-detail-ids" @change="GET_TRACE_SPANS({ 
traceId: i })">
+        <select class="rk-trace-detail-ids" @change="changeTraceId(i)">
           <option v-for="i in current.traceIds" :value="i" :key="i">{{ i 
}}</option>
         </select>
         <svg class="icon vm grey link-hover cp ml-5" 
@click="handleClick(current.traceIds)">
@@ -89,22 +99,31 @@ limitations under the License. -->
   import { Trace, Span } from '@/types/trace';
   import { Action, State } from 'vuex-class';
   import copy from '@/utils/copy';
+  import { State as traceState } from '@/store/modules/trace/index';
+  import LogTable from '../log/log-table/log-table.vue';
 
   @Component({
     components: {
       TraceDetailChartList,
       TraceDetailChartTree,
       TraceDetailChartTable,
+      LogTable,
     },
   })
   export default class TraceDetail extends Vue {
-    @State('rocketbot') private rocketbot: any;
+    @State('rocketTrace') private rocketTrace!: traceState;
     @Action('rocketTrace/GET_TRACE_SPANS') private GET_TRACE_SPANS: any;
+    @Action('rocketTrace/GET_TRACE_SPAN_LOGS') private GET_TRACE_SPAN_LOGS: 
any;
     @Prop() private spans!: Span[];
     @Prop() private current!: Trace;
     private mode: boolean = true;
     private displayMode: string = 'list';
-    private handleClick(ids: any) {
+    private showTraceLogs: boolean = false;
+    private pageSize: number = 10;
+    private pageNum: number = 1;
+    private traceId: string = '';
+
+    private handleClick(ids: string[]) {
       let copyValue = null;
       if (ids.length === 1) {
         copyValue = ids[0];
@@ -113,6 +132,29 @@ limitations under the License. -->
       }
       copy(copyValue);
     }
+
+    private changeTraceId(i: string) {
+      this.traceId = i;
+      this.GET_TRACE_SPANS({ traceId: i });
+    }
+
+    private turnLogsPage(pageNum: number) {
+      this.pageNum = pageNum;
+      this.searchTraceLogs();
+    }
+
+    private searchTraceLogs() {
+      this.showTraceLogs = true;
+      this.GET_TRACE_SPAN_LOGS({
+        condition: {
+          state: 'ALL',
+          relatedTrace: {
+            traceId: this.traceId || this.current.traceIds[0],
+          },
+          paging: { pageNum: this.pageNum, pageSize: this.pageSize, needTotal: 
true },
+        },
+      });
+    }
   }
 </script>
 
diff --git a/src/views/components/trace/trace-search.vue 
b/src/views/components/trace/trace-search.vue
index 709ee7b..0b3354f 100644
--- a/src/views/components/trace/trace-search.vue
+++ b/src/views/components/trace/trace-search.vue
@@ -114,11 +114,14 @@ limitations under the License. -->
   import { Component, Vue, Watch } from 'vue-property-decorator';
   import { Action, Getter, Mutation, State } from 'vuex-class';
   import TraceSelect from '../common/trace-select.vue';
+  import LogTable from '../log/log-table/log-table.vue';
+  import { State as traceState } from '@/store/modules/trace/index';
+  import { State as globalState } from '@/store/modules/global/index';
 
-  @Component({ components: { TraceSelect } })
+  @Component({ components: { TraceSelect, LogTable } })
   export default class TraceSearch extends Vue {
-    @State('rocketbot') private rocketbotGlobal: any;
-    @State('rocketTrace') private rocketTrace: any;
+    @State('rocketbot') private rocketbotGlobal!: globalState;
+    @State('rocketTrace') private rocketTrace!: traceState;
     @Getter('durationTime') private durationTime: any;
     @Getter('duration') private duration: any;
     @Action('RESET_DURATION') private RESET_DURATION: any;
@@ -158,6 +161,7 @@ limitations under the License. -->
         });
       }
     }
+
     private dateFormat(date: Date, step: string) {
       const year = date.getFullYear();
       const monthTemp = date.getMonth() + 1;
@@ -232,11 +236,11 @@ limitations under the License. -->
         queryDuration: this.globalTimeFormat([
           new Date(
             this.time[0].getTime() +
-              (parseInt(this.rocketbotGlobal.utc, 10) + new 
Date().getTimezoneOffset() / 60) * 3600000,
+              (parseInt(String(this.rocketbotGlobal.utc), 10) + new 
Date().getTimezoneOffset() / 60) * 3600000,
           ),
           new Date(
             this.time[1].getTime() +
-              (parseInt(this.rocketbotGlobal.utc, 10) + new 
Date().getTimezoneOffset() / 60) * 3600000,
+              (parseInt(String(this.rocketbotGlobal.utc), 10) + new 
Date().getTimezoneOffset() / 60) * 3600000,
           ),
         ]),
         traceState: this.traceState.key,
@@ -328,6 +332,9 @@ limitations under the License. -->
 </script>
 
 <style lang="scss">
+  .rk-log-box {
+    color: #3d444f;
+  }
   .rk-trace-search {
     flex-shrink: 0;
     background-color: #333840;
@@ -388,16 +395,22 @@ limitations under the License. -->
     }
   }
 
-  .rk-trace-search-btn {
+  .rk-trace-search-btn,
+  .rk-trace-log-btn {
     padding: 3px 9px;
     background-color: #484b55;
     border-radius: 4px;
-    margin-top: 12px;
+    color: #eee;
+    font-weight: normal;
+    cursor: pointer;
 
     &.bg-blue {
       background-color: #448dfe;
     }
   }
+  .rk-trace-search-btn {
+    margin-top: 12px;
+  }
 
   .rk-trace-clear-btn {
     padding: 3px 9px;
diff --git a/src/views/components/trace/trace-span-logs.vue 
b/src/views/components/trace/trace-span-logs.vue
new file mode 100644
index 0000000..0f19df8
--- /dev/null
+++ b/src/views/components/trace/trace-span-logs.vue
@@ -0,0 +1,152 @@
+<!-- Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License. -->
+<template>
+  <div>
+    <div class="rk-trace-detail">
+      <h5 class="mb-15">{{ $t('tags') }}.</h5>
+      <div class="mb-10 clear">
+        <span class="g-sm-4 grey">{{ $t('service') }}:</span>
+        <span class="g-sm-8 wba">{{ this.currentSpan.serviceCode }}</span>
+      </div>
+      <div class="mb-10 clear">
+        <span class="g-sm-4 grey">{{ $t('endpoint') }}:</span>
+        <span class="g-sm-8 wba">{{ this.currentSpan.label }}</span>
+      </div>
+      <div class="mb-10 clear">
+        <span class="g-sm-4 grey">{{ $t('spanType') }}:</span>
+        <span class="g-sm-8 wba">{{ this.currentSpan.type }}</span>
+      </div>
+      <div class="mb-10 clear">
+        <span class="g-sm-4 grey">{{ $t('component') }}:</span>
+        <span class="g-sm-8 wba">{{ this.currentSpan.component }}</span>
+      </div>
+      <div class="mb-10 clear">
+        <span class="g-sm-4 grey">Peer:</span>
+        <span class="g-sm-8 wba">{{ this.currentSpan.peer || 'No Peer' 
}}</span>
+      </div>
+      <div class="mb-10 clear">
+        <span class="g-sm-4 grey">{{ $t('error') }}:</span>
+        <span class="g-sm-8 wba">{{ this.currentSpan.isError }}</span>
+      </div>
+      <div class="mb-10 clear" v-for="i in this.currentSpan.tags" :key="i.key">
+        <span class="g-sm-4 grey">{{ i.key }}:</span>
+        <span class="g-sm-8 wba">
+          {{ i.value }}
+          <svg v-if="i.key === 'db.statement'" class="icon vm grey link-hover 
cp ml-5" @click="copy(i.value)">
+            <use xlink:href="#review-list"></use>
+          </svg>
+        </span>
+      </div>
+      <h5 class="mb-10" v-if="this.currentSpan.logs" 
v-show="this.currentSpan.logs.length">{{ $t('logs') }}.</h5>
+      <div v-for="(i, index) in this.currentSpan.logs" :key="index">
+        <div class="mb-10 sm">
+          <span class="mr-10">{{ $t('time') }}:</span><span class="grey">{{ 
i.time | dateformat }}</span>
+        </div>
+        <div class="mb-15 clear" v-for="(_i, _index) in i.data" :key="_index">
+          <div class="mb-10">
+            {{ _i.key }}:<span
+              v-if="_i.key === 'stack'"
+              class="r rk-sidebox-magnify"
+              @click="showCurrentSpanDetail(_i.key, _i.value)"
+            >
+              <svg class="icon">
+                <use xlink:href="#magnify"></use>
+              </svg>
+            </span>
+          </div>
+          <pre class="pl-15 mt-0 mb-0 sm oa">{{ _i.value }}</pre>
+        </div>
+      </div>
+      <div @click="getTaceLogs()">
+        <a class="rk-popup-btn bg-blue r">
+          <span class="mr-5 vm">
+            {{ $t('relatedTraceLogs') }}
+          </span>
+        </a>
+      </div>
+    </div>
+    <rk-sidebox :width="'100%'" :show.sync="showRelatedLogs" 
:title="$t('relatedTraceLogs')">
+      <div>
+        <RkPage
+          :currentSize="pageSize"
+          :currentPage="pageNum"
+          @changePage="turnPage"
+          :total="rocketTrace.traceSpanLogsTotal"
+        />
+        <LogServiceDetail :data="rocketTrace.traceSpanLogs || []" 
:loading="false" :noLink="true" />
+      </div>
+    </rk-sidebox>
+  </div>
+</template>
+<script lang="ts">
+  import { Component, Prop, Vue } from 'vue-property-decorator';
+  import LogServiceDetail from '../log/log-service-detail.vue';
+  import { Action, State } from 'vuex-class';
+  import copy from '@/utils/copy';
+  import { State as traceState } from '@/store/modules/trace/index';
+
+  @Component({
+    components: { LogServiceDetail },
+  })
+  export default class TraceSpanLogs extends Vue {
+    @State('rocketTrace') private rocketTrace!: traceState;
+    @Action('rocketTrace/GET_TRACE_SPAN_LOGS') private GET_TRACE_SPAN_LOGS: 
any;
+    @Prop() private currentSpan: any;
+    private showRelatedLogs: boolean = false;
+    private copy = copy;
+    private pageNum: number = 1;
+    private pageSize: number = 10;
+
+    private getTaceLogs() {
+      this.showRelatedLogs = true;
+      this.GET_TRACE_SPAN_LOGS({
+        condition: {
+          state: 'ALL',
+          relatedTrace: {
+            traceId: this.currentSpan.traceId,
+            segmentId: this.currentSpan.segmentId,
+            spanId: this.currentSpan.spanId,
+          },
+          paging: { pageNum: this.pageNum, pageSize: this.pageSize, needTotal: 
true },
+        },
+      });
+    }
+    private turnPage(pageNum: number) {
+      this.pageNum = pageNum;
+      this.getTaceLogs();
+    }
+    private showCurrentSpanDetail(title: string, text: string) {
+      const textLineNumber = text.split('\n').length;
+      let textHeight = textLineNumber * 20.2 + 10;
+      const tmpHeight = window.innerHeight * 0.9;
+      textHeight = textHeight >= tmpHeight ? tmpHeight : textHeight;
+      this.$modal.show('dialog', {
+        title,
+        text: `<div style="height:${textHeight}px">${text}</div>`,
+        buttons: [
+          {
+            title: 'Copy',
+            handler: () => {
+              this.copy(text);
+            },
+          },
+          {
+            title: 'Close',
+          },
+        ],
+      });
+    }
+  }
+</script>
diff --git a/src/views/components/trace/trace-table.vue 
b/src/views/components/trace/trace-table.vue
index 06af196..e8c1029 100644
--- a/src/views/components/trace/trace-table.vue
+++ b/src/views/components/trace/trace-table.vue
@@ -64,10 +64,11 @@ limitations under the License. -->
 <script lang="ts">
   import { Component, Vue, Prop, Watch } from 'vue-property-decorator';
   import { Action, Getter, Mutation, State } from 'vuex-class';
+  import { State as traceState } from '@/store/modules/trace/index';
+
   @Component
   export default class TraceTable extends Vue {
-    @State('rocketTrace') private rocketTrace: any;
-    @State('rocketbot') private rocketbot: any;
+    @State('rocketTrace') private rocketTrace!: traceState;
     @Mutation('rocketTrace/SET_TRACE_FORM_ITEM')
     private SET_TRACE_FORM_ITEM: any;
     @Mutation('rocketTrace/SET_CURRENT_TRACE') private SET_CURRENT_TRACE: any;

Reply via email to