Feat: Implement service logs in ui (#417)

diff --git a/src/assets/lang/en.ts b/src/assets/lang/en.ts
index a4fb0d2..c7201e5 100644
--- a/src/assets/lang/en.ts
+++ b/src/assets/lang/en.ts
@@ -171,10 +171,10 @@
   defaultOrder: 'Default Order',
   chartType: 'Chart Type',
   currentDepth: 'Current Depth',
-  traceTagsTip:
+  tagsTip:
     'Only tags defined in the core/default/searchableTagKeys are searchable. Check more details on the Configuration Vocabulary page',
-  traceLink: 'Configuration Vocabulary page',
-  traceAddTag: 'Please add a tag',
+  tagsLink: 'Configuration Vocabulary page',
+  addTag: 'Please add a tag',
   log: 'Log',
   logCategory: 'Log Category',
   errorCatalog: 'Error Catalog',
@@ -186,6 +186,14 @@
   errorPage: 'Error Page',
   category: 'Category',
   grade: 'Grade',
+  setConditions: 'More Conditions',
+  metricName: 'Metric Name',
+  keywordsOfContent: 'Keys Of Content',
+  excludingKeywordsOfContent: 'Exclude Keys Of Content',
+  return: 'Return',
+  isError: 'Error',
+  contentType: 'Content Type',
+  content: 'Content',
 };
 
 export default m;
diff --git a/src/assets/lang/zh.ts b/src/assets/lang/zh.ts
index fe8fda6..e696d0f 100644
--- a/src/assets/lang/zh.ts
+++ b/src/assets/lang/zh.ts
@@ -171,9 +171,9 @@
   defaultOrder: '默认顺序',
   chartType: '图表类型',
   currentDepth: '当前深度',
-  traceTagsTip: '只有core/default/searchableTagKeys中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。',
-  traceLink: '配置词汇页',
-  traceAddTag: '请添加标签',
+  tagsTip: '只有core/default/searchableTagKeys中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。',
+  tagsLink: '配置词汇页',
+  addTag: '请添加标签',
   log: '日志',
   logCategory: '日志类别',
   errorCatalog: '错误类目',
@@ -185,6 +185,14 @@
   errorPage: '错误页面',
   category: '类别',
   grade: '等级',
+  setConditions: '更多条件',
+  metricName: '指标名称',
+  keywordsOfContent: '内容关键词',
+  excludingKeywordsOfContent: '内容不包含的关键词',
+  return: '返回',
+  isError: '错误',
+  contentType: '内容类型',
+  content: '内容',
 };
 
 export default m;
diff --git a/src/graph/fragments/log.ts b/src/graph/fragments/log.ts
index 20d6841..163c708 100644
--- a/src/graph/fragments/log.ts
+++ b/src/graph/fragments/log.ts
@@ -34,21 +34,34 @@
     }`,
 };
 
-export const GetProfileAnalyze = {
-  variable: '$segmentId: String!, $timeRanges: [ProfileAnalyzeTimeRange!]!',
+export const QueryServiceLogs = {
+  variable: '$condition: LogQueryCondition',
   query: `
-  getProfileAnalyze: getProfileAnalyze(segmentId: $segmentId, timeRanges: $timeRanges) {
-    tip
-    trees {
-      elements {
-        id
-        parentId
-        codeSignature
-        duration
-        durationChildExcluded
-        count
-      }
-    }
-  }
-  `,
+    queryLogs(condition: $condition) {
+        logs {
+          serviceName
+          serviceId
+          serviceInstanceName
+          serviceInstanceId
+          endpointName
+          endpointId
+          traceId
+          timestamp
+          isError
+          statusCode
+          contentType
+          content
+          tags {
+            key
+            value
+          }
+        }
+        total
+    }`,
+};
+
+export const QueryLogsByKeywords = {
+  variable: '',
+  query: `
+  support: supportQueryLogsByKeywords`,
 };
diff --git a/src/graph/query/log.ts b/src/graph/query/log.ts
index 20db18e..66ff97e 100644
--- a/src/graph/query/log.ts
+++ b/src/graph/query/log.ts
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
-import { QueryBrowserErrorLogs } from '../fragments/log';
+import { QueryBrowserErrorLogs, QueryServiceLogs, QueryLogsByKeywords } from '../fragments/log';
 
 export const queryBrowserErrorLogs = `query queryBrowserErrorLogs(${QueryBrowserErrorLogs.variable}) {${QueryBrowserErrorLogs.query}}`;
+export const queryServiceLogs = `query queryLogs(${QueryServiceLogs.variable}) {${QueryServiceLogs.query}}`;
+export const queryLogsByKeywords = `query queryLogsByKeywords {${QueryLogsByKeywords.query}}`;
diff --git a/src/router.ts b/src/router.ts
index fffe4dd..8250755 100644
--- a/src/router.ts
+++ b/src/router.ts
@@ -48,8 +48,10 @@
           component: Dashboard,
         },
         {
+          name: 'trace',
           path: 'trace',
           component: Trace,
+          props: true,
         },
         {
           path: 'topology',
diff --git a/src/store/index.ts b/src/store/index.ts
index ede1c32..0e907fa 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -18,7 +18,7 @@
 import Vue from 'vue';
 import Vuex from 'vuex';
 import rocketbot, { State as RocketbotState } from './modules/global';
-import rocketOption, { State as DashboardOptionState } from './modules/dashboard/dashboard-option';
+import rocketOption, { State as DashboardOptionState } from './modules/global/selectors';
 import rocketData, { State as DashboardDataState } from './modules/dashboard/dashboard-data';
 import rocketTopo, { State as TopoState } from '@/store/modules/topology';
 import rocketTopoGroup, { State as TopoGroupState } from '@/store/modules/topology/group';
diff --git a/src/store/modules/dashboard/dashboard-data.ts b/src/store/modules/dashboard/dashboard-data.ts
index fc4e60d..1d17125 100644
--- a/src/store/modules/dashboard/dashboard-data.ts
+++ b/src/store/modules/dashboard/dashboard-data.ts
@@ -60,7 +60,6 @@
     }
     context.commit('SET_GROUP_QUERY', temp);
     context.commit('SET_CURRENT_GROUP', index);
-    context.dispatch('SET_CURRENT_STATE', context.state.tree[index].query);
     context.dispatch('RUN_EVENTS', {}, { root: true });
   },
   MIXHANDLE_CHANGE_GROUP_WITH_CURRENT(
@@ -83,7 +82,6 @@
     }
     context.commit('SET_GROUP_QUERY', temp);
     context.commit('SET_CURRENT_GROUP_WITH_CURRENT', { index, current });
-    context.dispatch('SET_CURRENT_STATE', context.state.tree[index].query);
     context.dispatch('RUN_EVENTS', {}, { root: true });
   },
   TYPE_METRICS(context, params: { name: string }) {
diff --git a/src/store/modules/dashboard/mutation-types.ts b/src/store/modules/dashboard/mutation-types.ts
index 110b0dd..aa18646 100644
--- a/src/store/modules/dashboard/mutation-types.ts
+++ b/src/store/modules/dashboard/mutation-types.ts
@@ -35,6 +35,7 @@
 export const SET_INSTANCE_INFO = 'SET_INSTANCE_INFO';
 export const SET_TEMPLATES = 'SET_TEMPLATES';
 export const UPDATE_DASHBOARD = 'UPDATE_DASHBOARD';
+export const SET_PAGE_TYPE = 'SET_PAGE_TYPE';
 
 // comp
 export const SET_CURRENT_GROUP = 'SET_CURRENT_GROUP';
diff --git a/src/store/modules/dashboard/dashboard-option.ts b/src/store/modules/global/selectors.ts
similarity index 87%
rename from src/store/modules/dashboard/dashboard-option.ts
rename to src/store/modules/global/selectors.ts
index f9ac1ee..354ee72 100644
--- a/src/store/modules/dashboard/dashboard-option.ts
+++ b/src/store/modules/global/selectors.ts
@@ -16,9 +16,10 @@
  */
 
 import { Commit, ActionTree, MutationTree, Dispatch } from 'vuex';
-import * as types from './mutation-types';
+import * as types from '../dashboard/mutation-types';
 import { AxiosResponse } from 'axios';
 import graph from '@/graph';
+import { Duration } from '@/types/global';
 
 interface Options {
   key: string;
@@ -34,8 +35,11 @@
   instances: Options[];
   currentInstance: Options;
   updateDashboard: object;
+  pageType: string;
 }
 
+const LOG = 'Log';
+
 const initState: State = {
   services: [],
   currentService: { key: '', label: '' },
@@ -46,13 +50,14 @@
   databases: [],
   currentDatabase: { key: '', label: '' },
   updateDashboard: {},
+  pageType: '',
 };
 
 // mutations
 const mutations: MutationTree<State> = {
   [types.SET_SERVICES](state: State, data: Options[]) {
-    state.services = data;
-    state.currentService = data[0] || {};
+    state.services = state.pageType === LOG ? [{ label: 'All', key: '' }, ...data] : data;
+    state.currentService = state.services[0] || {};
   },
   [types.SET_CURRENT_SERVICE](state: State, service: Options) {
     state.currentService = service;
@@ -64,24 +69,24 @@
   },
 
   [types.SET_ENDPOINTS](state: State, data: Options[]) {
-    state.endpoints = data;
-    if (!data.length) {
+    state.endpoints = state.pageType === LOG ? [{ label: 'All', key: '' }, ...data] : data;
+    if (!state.endpoints.length) {
       state.currentEndpoint = { key: '', label: '' };
       return;
     }
-    state.currentEndpoint = data[0];
+    state.currentEndpoint = state.endpoints[0];
   },
   [types.SET_CURRENT_ENDPOINT](state: State, endpoint: Options) {
     state.currentEndpoint = endpoint;
     state.updateDashboard = endpoint;
   },
   [types.SET_INSTANCES](state: State, data: Options[]) {
-    state.instances = data;
-    if (!data.length) {
+    state.instances = state.pageType === LOG ? [{ label: 'All', key: '' }, ...data] : data;
+    if (!state.instances.length) {
       state.currentInstance = { key: '', label: '' };
       return;
     }
-    state.currentInstance = data[0];
+    state.currentInstance = state.instances[0];
   },
   [types.SET_CURRENT_INSTANCE](state: State, instance: Options) {
     state.currentInstance = instance;
@@ -99,6 +104,9 @@
     state.currentDatabase = service;
     state.updateDashboard = service;
   },
+  [types.SET_PAGE_TYPE](state: State, type: string) {
+    state.pageType = type;
+  },
 };
 
 // actions
@@ -150,9 +158,6 @@
       });
   },
   SELECT_SERVICE(context: { commit: Commit; dispatch: Dispatch }, params: any) {
-    if (!params.service.key) {
-      return;
-    }
     context.commit('SET_CURRENT_SERVICE', params.service);
     context.dispatch('GET_SERVICE_ENDPOINTS', {});
     context.dispatch('GET_SERVICE_INSTANCES', { duration: params.duration });
@@ -167,13 +172,16 @@
     context.commit('SET_CURRENT_DATABASE', params);
     context.dispatch('RUN_EVENTS', {}, { root: true });
   },
-  SET_CURRENT_STATE(context: { commit: Commit }, params: any = {}) {
-    context.commit(types.SET_CURRENT_SERVICE, params.service ? params.service : {});
-    context.commit(types.SET_CURRENT_DATABASE, params.database ? params.database : {});
-    context.commit(types.SET_CURRENT_ENDPOINT, params.endpoint ? params.endpoint : {});
-    context.commit(types.SET_CURRENT_INSTANCE, params.instance ? params.instance : {});
-  },
-  MIXHANDLE_GET_OPTION(context: { dispatch: Dispatch; state: State }, params: any) {
+  MIXHANDLE_GET_OPTION(
+    context: { dispatch: Dispatch; commit: Commit },
+    params: {
+      compType: string;
+      duration: Duration;
+      keywordServiceName?: string;
+      pageType?: string;
+    },
+  ) {
+    context.commit('SET_PAGE_TYPE', params.pageType);
     switch (params.compType) {
       case 'service':
         return context
diff --git a/src/store/modules/log/index.ts b/src/store/modules/log/index.ts
index d4cedb9..3b9a66f 100644
--- a/src/store/modules/log/index.ts
+++ b/src/store/modules/log/index.ts
@@ -25,22 +25,19 @@
   label: string;
 }
 export interface State {
-  type: any;
-  logCategories: any[];
+  type: Options;
+  logCategories: Options[];
   logs: any[];
   total: number;
-  categories: any[];
-  category: any;
+  categories: Options[];
+  category: Options;
   loading: boolean;
-  logServices: Options[];
-  currentLogService: Options;
-  logEndpoints: Options[];
-  currentLogEndpoint: Options;
-  logInstances: Options[];
-  currentLogInstance: Options;
+  conditions: any;
+  supportQueryLogsByKeywords: boolean;
+  tagsList: string[];
 }
 
-const categories: any = [
+const categories: Options[] = [
   { label: 'All', key: 'ALL' },
   { label: 'Ajax', key: 'AJAX' },
   { label: 'Resource', key: 'RESOURCE' },
@@ -50,23 +47,20 @@
   { label: 'Unknown', key: 'UNKNOWN' },
 ];
 
-const initState: State = {
-  type: { label: 'Browser', key: 'browser' },
+const logState: State = {
+  type: { label: 'Service', key: 'service' },
   logCategories: [
+    { label: 'Service', key: 'service' },
     { label: 'Browser', key: 'browser' },
-    { label: 'Service', key: 'service', disabled: true },
   ],
   logs: [],
   total: 0,
   categories,
   category: { label: 'All', key: 'ALL' },
   loading: false,
-  logServices: [],
-  currentLogService: { key: '', label: '' },
-  logEndpoints: [],
-  currentLogEndpoint: { key: '', label: '' },
-  logInstances: [],
-  currentLogInstance: { key: '', label: '' },
+  conditions: {},
+  supportQueryLogsByKeywords: true,
+  tagsList: localStorage.getItem('logTags') ? JSON.parse(localStorage.getItem('logTags') || '') : [],
 };
 
 // mutations
@@ -86,39 +80,39 @@
   [types.SET_LOADING](state: State, data: boolean) {
     state.loading = data;
   },
-  [types.SET_LOG_SERVICES](state: State, data: Options[]) {
-    state.logServices = [{ label: 'All', key: '' }, ...data];
-    state.currentLogService = state.logServices[0];
+  [types.SET_LOG_CONDITIONS](state: State, item: Options) {
+    state.conditions = {
+      ...state.conditions,
+      [item.label]: item.key,
+    };
   },
-  [types.SET_LOG_ENDPOINTS](state: State, data: Options[]) {
-    state.logEndpoints = [{ label: 'All', key: '' }, ...data];
-    state.currentLogEndpoint = state.logEndpoints[0];
+  [types.SET_SUPPORT_QUERY_LOGS_KEYWORDS](state: State, isSupport: boolean) {
+    state.supportQueryLogsByKeywords = isSupport;
   },
-  [types.SET_LOG_INSTANCES](state: State, data: Options[]) {
-    state.logInstances = [{ label: 'All', key: '' }, ...data];
-    state.currentLogInstance = state.logInstances[0];
+  [types.CLEAR_LOG_CONDITIONS](state: State) {
+    state.conditions = {};
   },
-  [types.SET_CURRENT_LOG_SERVICE](state: State, service: Options) {
-    state.currentLogService = service;
-  },
-  [types.SET_CURRENT_LOG_ENDPOINT](state: State, endpoint: Options) {
-    state.currentLogEndpoint = endpoint;
-  },
-  [types.SET_CURRENT_LOG_INSTANCE](state: State, instance: Options) {
-    state.currentLogInstance = instance;
+  [types.SET_TAG_LIST](state: State, data: string[]) {
+    state.tagsList = data;
   },
 };
 
 // actions
 const actions: ActionTree<State, any> = {
   QUERY_LOGS(context: { commit: Commit; state: State }, params: any) {
+    context.commit('SET_LOADING', true);
     switch (context.state.type.key) {
       case 'browser':
-        context.commit('SET_LOADING', true);
         return graph
           .query('queryBrowserErrorLogs')
           .params(params)
           .then((res: AxiosResponse<any>) => {
+            if (res.data && res.data.errors) {
+              context.commit('SET_LOGS', []);
+              context.commit('SET_LOGS_TOTAL', 0);
+
+              return;
+            }
             context.commit('SET_LOGS', res.data.data.queryBrowserErrorLogs.logs);
             context.commit('SET_LOGS_TOTAL', res.data.data.queryBrowserErrorLogs.total);
           })
@@ -126,68 +120,41 @@
             context.commit('SET_LOADING', false);
           });
       case 'service':
-        break;
+        return graph
+          .query('queryServiceLogs')
+          .params(params)
+          .then((res: AxiosResponse<any>) => {
+            if (res.data && res.data.errors) {
+              context.commit('SET_LOGS', []);
+              context.commit('SET_LOGS_TOTAL', 0);
+
+              return;
+            }
+            context.commit('SET_LOGS', res.data.data.queryLogs.logs);
+            context.commit('SET_LOGS_TOTAL', res.data.data.queryLogs.total);
+          })
+          .finally(() => {
+            context.commit('SET_LOADING', false);
+          });
       default:
         break;
     }
   },
-  GET_LOG_SERVICES(context: { commit: Commit }, params: { duration: any }) {
+  QUERY_LOGS_BYKEYWORDS(context: { commit: Commit }) {
     return graph
-      .query('queryBrowserServices')
-      .params(params)
-      .then((res: AxiosResponse) => {
-        context.commit(types.SET_LOG_SERVICES, res.data.data.services);
+      .query('queryLogsByKeywords')
+      .params({})
+      .then((res: AxiosResponse<any>) => {
+        if (res.data && res.data.errors) {
+          return;
+        }
+        context.commit('SET_SUPPORT_QUERY_LOGS_KEYWORDS', res.data.data.support);
       });
   },
-  LOG_GET_OPTION(context: { dispatch: Dispatch; state: State }, params: any) {
-    context
-      .dispatch('GET_LOG_SERVICES', { duration: params.duration })
-      .then(() => context.dispatch('GET_LOG_ENDPOINTS', {}))
-      .then(() => context.dispatch('GET_LOG_INSTANCES', { duration: params.duration }));
-  },
-  GET_LOG_ENDPOINTS(context: { commit: Commit; state: any }, params: { keyword: string }) {
-    if (!context.state.currentLogEndpoint.key) {
-      context.commit(types.SET_LOG_ENDPOINTS, []);
-      return;
-    }
-    if (!params.keyword) {
-      params.keyword = '';
-    }
-    return graph
-      .query('queryEndpoints')
-      .params({ serviceId: context.state.currentLogEndpoint.key || '', ...params })
-      .then((res: AxiosResponse) => {
-        context.commit(types.SET_LOG_ENDPOINTS, res.data.data.getEndpoints);
-      });
-  },
-  GET_LOG_INSTANCES(context: { commit: Commit; state: any }, params: any) {
-    if (!context.state.currentLogInstance.key) {
-      context.commit(types.SET_LOG_INSTANCES, []);
-      return;
-    }
-    return graph
-      .query('queryInstances')
-      .params({ serviceId: context.state.currentLogInstance.key || '', ...params })
-      .then((res: AxiosResponse) => {
-        context.commit(types.SET_LOG_INSTANCES, res.data.data.getServiceInstances);
-      });
-  },
-  SELECT_LOG_SERVICE(context: { commit: Commit; dispatch: Dispatch }, params: any) {
-    context.commit('SET_CURRENT_LOG_SERVICE', params.service);
-    context.dispatch('GET_LOG_ENDPOINTS', {});
-    context.dispatch('GET_LOG_INSTANCES', { duration: params.duration });
-  },
-  SELECT_LOG_ENDPOINT(context: { commit: Commit; dispatch: Dispatch; state: any; rootState: any }, params: any) {
-    context.commit('SET_CURRENT_LOG_ENDPOINT', params.endpoint);
-  },
-  SELECT_LOG_INSTANCE(context: { commit: Commit; dispatch: Dispatch; state: any; rootState: any }, params: any) {
-    context.commit('SET_CURRENT_LOG_INSTANCE', params.instance);
-  },
 };
 
 export default {
-  // namespaced: true,
-  state: initState,
+  state: logState,
   actions,
   mutations,
 };
diff --git a/src/store/mutation-types.ts b/src/store/mutation-types.ts
index 603e45a..6846c00 100644
--- a/src/store/mutation-types.ts
+++ b/src/store/mutation-types.ts
@@ -122,3 +122,7 @@
 export const SET_CURRENT_LOG_SERVICE = 'SET_CURRENT_LOG_SERVICE';
 export const SET_CURRENT_LOG_ENDPOINT = 'SET_CURRENT_LOG_ENDPOINT';
 export const SET_CURRENT_LOG_INSTANCE = 'SET_CURRENT_LOG_INSTANCE';
+export const SET_LOG_CONDITIONS = 'SET_LOG_CONDITIONS';
+export const SET_SUPPORT_QUERY_LOGS_KEYWORDS = 'SET_SUPPORT_QUERY_LOGS_KEYWORDS';
+export const CLEAR_LOG_CONDITIONS = 'CLEAR_LOG_CONDITIONS';
+export const SET_TAG_LIST = 'SET_TAG_LIST';
diff --git a/src/utils/formatJson.ts b/src/utils/formatJson.ts
new file mode 100644
index 0000000..02bda02
--- /dev/null
+++ b/src/utils/formatJson.ts
@@ -0,0 +1,25 @@
+/**
+ * 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.
+ */
+const censor = (key: any, value: any) => {
+  if (typeof value === 'function') {
+    return Function.prototype.toString.call(value);
+  }
+  return value;
+};
+export const formatJson = (data: JSON) => {
+  return JSON.stringify(data, censor, 2);
+};
diff --git a/src/views/components/common/trace-detail-chart-table.vue b/src/views/components/common/trace-detail-chart-table.vue
index 9203931..52c8048 100644
--- a/src/views/components/common/trace-detail-chart-table.vue
+++ b/src/views/components/common/trace-detail-chart-table.vue
@@ -80,7 +80,6 @@
         </div>
       </div>
     </rk-sidebox>
-    <v-dialog width="90%" />
   </div>
 </template>
 <style lang="scss">
diff --git a/src/views/components/dashboard/dashboard-item.vue b/src/views/components/dashboard/dashboard-item.vue
index 526601d..1638dc0 100644
--- a/src/views/components/dashboard/dashboard-item.vue
+++ b/src/views/components/dashboard/dashboard-item.vue
@@ -72,7 +72,7 @@
   import { MetricsType, CalculationType } from './charts/constant';
   import { uuid } from '@/utils/uuid.ts';
   import { State as globalState } from '@/store/modules/global';
-  import { State as optionState } from '@/store/modules/dashboard/dashboard-option';
+  import { State as optionState } from '@/store/modules/global/selectors';
 
   @Component({
     components: { ...charts },
diff --git a/src/views/components/log/log-bar.vue b/src/views/components/log/log-bar.vue
index bf4a5e0..1a4d14c 100644
--- a/src/views/components/log/log-bar.vue
+++ b/src/views/components/log/log-bar.vue
@@ -12,96 +12,126 @@
 limitations under the License. -->
 
 <template>
-  <div class="rk-error-log-bar flex-h">
-    <div class="flex-h">
-      <ToolBarSelect
-        @onChoose="SELECT_LOG_TYPE"
-        :title="this.$t('logCategory')"
-        :current="logState.type"
-        :data="logState.logCategories"
-        icon="chart"
-      />
-      <ToolBarSelect
-        @onChoose="selectService"
-        :title="this.$t('service')"
-        :current="logState.currentLogService"
-        :data="logState.logServices"
-        icon="package"
-      />
-      <ToolBarSelect
-        @onChoose="selectInstance"
-        :title="this.$t('version')"
-        :current="logState.currentLogInstance"
-        :data="logState.logInstances"
-        icon="disk"
-      />
-      <ToolBarSelect
-        @onChoose="selectEndpoint"
-        :title="this.$t('page')"
-        :current="logState.currentLogEndpoint"
-        :data="logState.logEndpoints"
-        icon="code"
-      />
-      <ToolBarSelect
-        @onChoose="SELECT_ERROR_CATALOG"
-        :title="this.$t('errorCatalog')"
-        :current="logState.category"
-        :data="logState.categories"
-        icon="epic"
-      />
+  <div class="rk-log-nav">
+    <div class="rk-error-log-bar flex-h">
+      <div class="flex-h">
+        <ToolBarSelect
+          @onChoose="selectCategroy"
+          :title="this.$t('logCategory')"
+          :current="logState.type"
+          :data="logState.logCategories"
+          icon="chart"
+        />
+        <ToolBarSelect
+          @onChoose="selectService"
+          :title="this.$t('service')"
+          :current="rocketOption.currentService"
+          :data="rocketOption.services"
+          icon="package"
+        />
+        <ToolBarSelect
+          @onChoose="selectInstance"
+          :title="logState.type.key === cateGoryBrowser ? this.$t('version') : this.$t('currentInstance')"
+          :current="rocketOption.currentInstance"
+          :data="rocketOption.instances"
+          icon="disk"
+        />
+        <ToolBarSelect
+          @onChoose="selectEndpoint"
+          :title="logState.type.key === cateGoryBrowser ? this.$t('page') : this.$t('currentEndpoint')"
+          :current="rocketOption.currentEndpoint"
+          :data="rocketOption.endpoints"
+          icon="code"
+        />
+        <ToolBarSelect
+          @onChoose="SELECT_ERROR_CATALOG"
+          :title="this.$t('errorCatalog')"
+          :current="logState.category"
+          :data="logState.categories"
+          icon="epic"
+        />
+      </div>
+      <span class="flex-h rk-right">
+        <a
+          class="rk-log-search-btn bg-blue mr-10"
+          v-if="logState.type.key !== cateGoryBrowser"
+          @click="openConditionsBox"
+        >
+          <rk-icon icon="settings" class="mr-5" />
+          <span class="vm">{{ $t('setConditions') }}</span>
+        </a>
+        <a class="rk-log-search-btn bg-blue mr-10" @click="queryLogs">
+          <rk-icon icon="search" class="mr-5" />
+          <span class="vm">{{ this.$t('search') }}</span>
+        </a>
+        <a class="rk-log-clear-btn r mr-10" @click="clearSearch">
+          <rk-icon icon="clear" class="mr-5" />
+          <span class="vm">{{ this.$t('clear') }}</span>
+        </a>
+
+        <RkPage :currentSize="10" :currentPage="pageNum" @changePage="handleRefresh" :total="logState.total" />
+      </span>
     </div>
-
-    <span class="flex-h rk-right">
-      <a class="rk-log-clear-btn r mr-10" @click="clearSearch">
-        <svg class="icon mr-5 vm">
-          <use xlink:href="#clear"></use>
-        </svg>
-        <span class="vm">{{ this.$t('clear') }}</span>
-      </a>
-      <a class="rk-log-search-btn bg-blue mr-10" @click="queryLogs">
-        <svg class="icon mr-5 vm">
-          <use xlink:href="#search"></use>
-        </svg>
-        <span class="vm">{{ this.$t('search') }}</span>
-      </a>
-
-      <RkPage :currentSize="10" :currentPage="pageNum" @changePage="handleRefresh" :total="logState.total" />
-    </span>
+    <div class="flex-h" v-show="showConditionsBox">
+      <LogConditions />
+    </div>
   </div>
 </template>
 
 <script lang="ts">
   import { Duration, Option } from '@/types/global';
-  import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
+  import { Component, Vue } from 'vue-property-decorator';
   import { Action, Getter, Mutation, State } from 'vuex-class';
   import TraceSelect from '../common/trace-select.vue';
   import ToolBarSelect from '../dashboard/tool-bar-select.vue';
   import ToolBarEndpointSelect from '../dashboard/tool-bar-endpoint-select.vue';
+  import LogConditions from './log-conditions.vue';
 
   @Component({
-    components: { TraceSelect, ToolBarSelect, ToolBarEndpointSelect },
+    components: { TraceSelect, ToolBarSelect, ToolBarEndpointSelect, LogConditions },
   })
   export default class Bar extends Vue {
     @State('rocketLog') private logState: any;
     @State('rocketOption') private rocketOption: any;
     @Mutation('SELECT_LOG_TYPE') private SELECT_LOG_TYPE: any;
     @Mutation('SELECT_ERROR_CATALOG') private SELECT_ERROR_CATALOG: any;
-    @Action('SELECT_LOG_SERVICE') private SELECT_LOG_SERVICE: any;
-    @Action('SELECT_LOG_ENDPOINT') private SELECT_LOG_ENDPOINT: any;
-    @Action('SELECT_LOG_INSTANCE') private SELECT_LOG_INSTANCE: any;
-    @Action('LOG_GET_OPTION') private LOG_GET_OPTION: any;
+    @Mutation('SET_EVENTS') private SET_EVENTS: any;
+    @Mutation('CLEAR_LOG_CONDITIONS') private CLEAR_LOG_CONDITIONS: any;
+    @Mutation('SET_TAG_LIST') private SET_TAG_LIST: any;
+    @Action('SELECT_SERVICE') private SELECT_SERVICE: any;
+    @Action('SELECT_ENDPOINT') private SELECT_ENDPOINT: any;
+    @Action('SELECT_INSTANCE') private SELECT_INSTANCE: any;
+    @Action('MIXHANDLE_GET_OPTION') private MIXHANDLE_GET_OPTION: any;
     @Action('QUERY_LOGS') private QUERY_LOGS: any;
+    @Action('QUERY_LOGS_BYKEYWORDS') private QUERY_LOGS_BYKEYWORDS: any;
     @Getter('durationTime') private durationTime: any;
 
     private pageNum: number = 1;
+    private cateGoryBrowser = 'browser';
+    private showConditionsBox = true;
+    private logPage = 'Log';
 
     private beforeMount() {
-      this.LOG_GET_OPTION({
+      this.MIXHANDLE_GET_OPTION({
         compType: this.logState.type.key,
         duration: this.durationTime,
-      }).then(() => {
-        this.queryLogs();
-      });
+        pageType: this.logPage,
+      })
+        .then(() => {
+          this.QUERY_LOGS_BYKEYWORDS();
+        })
+        .then(() => {
+          this.queryLogs();
+        });
+      this.SET_EVENTS([
+        () => {
+          this.queryLogs();
+        },
+      ]);
+    }
+
+    private beforeDestroy() {
+      this.SET_EVENTS([]);
     }
 
     private handleRefresh(pageNum: number) {
@@ -109,46 +139,90 @@
       this.queryLogs();
     }
 
-    private selectService(i: any) {
-      this.SELECT_LOG_SERVICE({ service: i, duration: this.durationTime });
+    private selectService(i: { key: string; label: string }) {
+      this.SELECT_SERVICE({ service: i, duration: this.durationTime });
     }
 
-    private selectEndpoint(i: any) {
-      this.SELECT_LOG_ENDPOINT({ endpoint: i, duration: this.durationTime });
+    private selectEndpoint(i: { key: string; label: string }) {
+      this.SELECT_ENDPOINT({ endpoint: i, duration: this.durationTime });
     }
 
-    private selectInstance(i: any) {
-      this.SELECT_LOG_INSTANCE({ instance: i, duration: this.durationTime });
+    private selectInstance(i: { key: string; label: string }) {
+      this.SELECT_INSTANCE({ instance: i, duration: this.durationTime });
     }
+
+    private selectCategroy(i: { key: string; label: string }) {
+      this.SELECT_LOG_TYPE(i);
+      this.MIXHANDLE_GET_OPTION({
+        compType: i.key,
+        duration: this.durationTime,
+        pageType: this.logPage,
+      }).then(() => {
+        this.queryLogs();
+      });
+    }
+
     private clearSearch() {
-      this.SELECT_LOG_SERVICE({ service: { label: 'All', key: '' }, duration: this.durationTime });
+      this.SELECT_SERVICE({ service: { label: 'All', key: '' }, duration: this.durationTime });
       this.SELECT_ERROR_CATALOG({ label: 'All', key: 'ALL' });
+      this.CLEAR_LOG_CONDITIONS();
+      this.queryLogs();
+      window.localStorage.removeItem('logTags');
+      this.SET_TAG_LIST([]);
     }
 
     private queryLogs() {
-      const { category, currentLogService, currentLogInstance, currentLogEndpoint } = this.logState;
+      const { category, conditions, type } = this.logState;
+      const { currentService, currentInstance, currentEndpoint } = this.rocketOption;
 
       this.QUERY_LOGS({
-        condition: {
-          serviceId: currentLogService.key,
-          serviceVersionId: currentLogInstance.key,
-          pagePathId: currentLogEndpoint.key,
-          category: category.key,
-          paging: { pageNum: this.pageNum, pageSize: 35, needTotal: true },
-          queryDuration: this.durationTime,
-        },
+        condition:
+          type.key === this.cateGoryBrowser
+            ? {
+                serviceId: currentService.key,
+                serviceVersionId: currentInstance.key,
+                pagePathId: currentEndpoint.key,
+                category: category.key,
+                paging: { pageNum: this.pageNum, pageSize: 35, needTotal: true },
+                queryDuration: this.durationTime,
+              }
+            : {
+                serviceId: currentService.key || undefined,
+                serviceInstanceId: currentInstance.key || undefined,
+                endpointId: currentEndpoint.key || undefined,
+                state: category.key,
+                excludingKeywordsOfContent:
+                  this.logState.supportQueryLogsByKeywords && conditions.excludingKeywordsOfContent
+                    ? conditions.excludingKeywordsOfContent.split(',')
+                    : undefined,
+                keywordsOfContent:
+                  this.logState.supportQueryLogsByKeywords && conditions.keywordsOfContent
+                    ? conditions.keywordsOfContent.split(',')
+                    : undefined,
+                relatedTrace: conditions.traceId ? { traceId: conditions.traceId } : undefined,
+                tags: conditions.tags,
+                paging: { pageNum: this.pageNum, pageSize: 35, needTotal: true },
+                queryDuration: conditions.traceId ? undefined : this.durationTime,
+              },
       });
     }
+
+    private openConditionsBox() {
+      this.showConditionsBox = !this.showConditionsBox;
+    }
   }
 </script>
 
 <style scoped lang="scss">
+  .rk-log-nav {
+    width: 100%;
+    background: #333840;
+  }
   .rk-error-log-bar {
     flex-shrink: 0;
     background-color: #333840;
     color: #eee;
     width: 100%;
-    padding: 8px 15px 12px;
     height: 52px;
     justify-content: space-between;
   }
@@ -161,7 +235,6 @@
     padding: 3px 9px;
     background-color: #484b55;
     border-radius: 4px;
-    /*margin-top: 12px;*/
     &.bg-blue {
       background-color: #448dfe;
     }
@@ -171,4 +244,7 @@
     background-color: #484b55;
     border-radius: 4px;
   }
+  .log-condition-box {
+    color: #333840;
+  }
 </style>
diff --git a/src/views/components/log/log-detail-table.vue b/src/views/components/log/log-browser-detail.vue
similarity index 66%
rename from src/views/components/log/log-detail-table.vue
rename to src/views/components/log/log-browser-detail.vue
index 307a560..902e28e 100644
--- a/src/views/components/log/log-detail-table.vue
+++ b/src/views/components/log/log-browser-detail.vue
@@ -24,24 +24,61 @@
     </LogTable>
     <rk-sidebox :width="'50%'" :show.sync="showDetail" :title="$t('logDetail')">
       <div class="rk-log-detail">
-        <div class="mb-10 clear rk-flex" v-for="(item, index) in columns">
+        <div class="mb-10 clear rk-flex" v-for="(item, index) in columns" :key="index">
           <template>
             <span class="g-sm-4 grey">{{ $t(item.value) }}:</span>
             <span
               v-if="['message', 'stack'].includes(item.label)"
               class="text"
-              v-html="lineBreak(currentSpan[item.label]) || '-'"
+              v-html="lineBreak(currentLog[item.label]) || '-'"
             ></span>
-            <span v-else-if="item.label === 'time'" class="g-sm-8 wba">{{ currentSpan[item.label] | dateformat }}</span>
-            <span v-else class="g-sm-8 wba">{{ currentSpan[item.label] || '-' }}</span>
+            <span v-else-if="item.label === 'time'" class="g-sm-8 wba">{{ currentLog[item.label] | dateformat }}</span>
+            <span v-else class="g-sm-8 wba">{{ currentLog[item.label] || '-' }}</span>
           </template>
         </div>
       </div>
     </rk-sidebox>
-
-    <v-dialog width="90%" />
   </div>
 </template>
+
+<script lang="ts">
+  import { Component, Prop, Vue } from 'vue-property-decorator';
+  import { Mutation, State } from 'vuex-class';
+  import LogTable from './log-table/log-table.vue';
+  import { BrowserLogConstants } from './log-table/log-constant';
+
+  @Component({
+    components: { LogTable },
+  })
+  export default class LogBrowserDetail extends Vue {
+    @State('rocketLog') private logState: any;
+    @Prop() private data: any;
+    @Prop() private loading!: true;
+    @Prop() private showBtnDetail: any;
+
+    private columns = BrowserLogConstants;
+    private showDetail = false;
+    private list = [];
+    private currentLog = {};
+    private created() {
+      this.$eventBus.$on('HANDLE-SELECT-LOG', this, this.handleSelectLog);
+    }
+    private lineBreak(str = '') {
+      const s = str
+        .replace(/</g, '&lt;')
+        .replace(/>/g, '&gt;')
+        .replace(/\r\n/g, '<br />')
+        .replace(/\n/g, '<br />');
+      return s;
+    }
+    private handleSelectLog(data: any) {
+      this.currentLog = data;
+      if (!this.showBtnDetail) {
+        this.showDetail = true;
+      }
+    }
+  }
+</script>
 <style lang="scss">
   .rk-tooltip-popper.log-table-tooltip .rk-tooltip-inner {
     max-width: 600px;
@@ -52,54 +89,6 @@
     border-bottom: none;
   }
 </style>
-
-<script lang="js">
-  import LogTable from './log-table/log-table.vue';
-  import { BrowserLogConstants } from './log-table/log-constant';
-  /* eslint-disable */
-  /* tslint:disable */
-  export default {
-    components: {
-      LogTable,
-    },
-    props: ['data', 'loading', 'showBtnDetail'],
-    data() {
-      return {
-        diaplay: true,
-        columns: BrowserLogConstants,
-        showDetail: false,
-        list: [],
-        currentSpan: {},
-      };
-    },
-    methods: {
-      lineBreak(str = '') {
-        let s = str
-                .replace(/</g, '&lt;')
-                .replace(/>/g, '&gt;')
-                .replace(/\r\n/g, '<br />')
-                .replace(/\n/g, '<br />');
-        return s;
-      },
-      handleSelectSpan(data) {
-        this.currentSpan = data;
-        if (!this.showBtnDetail) {
-          this.showDetail = true;
-        }
-        this.$emit('selectSpan', data);
-      },
-      handleViewSpan(data) {
-        this.showDetail = true;
-      }
-    },
-    created() {
-    },
-    mounted() {
-      this.$eventBus.$on('HANDLE-SELECT-SPAN', this, this.handleSelectSpan);
-      this.$eventBus.$on('HANDLE-VIEW-SPAN', this, this.handleViewSpan);
-    },
-  };
-</script>
 <style lang="scss" scoped>
   .rk-log-t-loading {
     text-align: center;
diff --git a/src/views/components/log/log-conditions.vue b/src/views/components/log/log-conditions.vue
new file mode 100644
index 0000000..4e584f1
--- /dev/null
+++ b/src/views/components/log/log-conditions.vue
@@ -0,0 +1,182 @@
+<!-- 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 class="rk-search-conditions flex-v">
+    <div class="flex-h">
+      <div class="mr-15">
+        <span class="sm b grey mr-10">{{ this.$t('traceID') }}:</span>
+        <input
+          type="text"
+          class="rk-trace-search-input dib"
+          @change="changeConditions($event, LogConditionsOpt.TraceID)"
+        />
+      </div>
+      <div class="mr-15">
+        <span class="sm b grey mr-10">{{ this.$t('keywordsOfContent') }}:</span>
+        <input
+          type="text"
+          class="rk-trace-search-input dib"
+          @change="changeConditions($event, LogConditionsOpt.KeywordsOfContent)"
+        />
+      </div>
+      <div class="mr-15">
+        <span class="sm b grey mr-10">{{ this.$t('excludingKeywordsOfContent') }}:</span>
+        <input
+          type="text"
+          class="rk-trace-search-input dib"
+          @change="changeConditions($event, LogConditionsOpt.ExcludingKeywordsOfContent)"
+        />
+      </div>
+    </div>
+    <div class="mr-10" style="padding-top: 10px">
+      <span class="sm grey">{{ this.$t('tags') }}: </span>
+      <span class="rk-trace-tags">
+        <span class="selected" v-for="(item, index) in rocketLog.tagsList" :key="index">
+          <span>{{ item }}</span>
+          <span class="remove-icon" @click="removeTags(index)">×</span>
+        </span>
+      </span>
+      <input type="text" :placeholder="this.$t('addTag')" v-model="tags" class="rk-trace-new-tag" @keyup="addLabels" />
+      <span class="trace-tips" v-tooltip:bottom="{ content: this.$t('tagsTip') }">
+        <a
+          target="blank"
+          href="https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/configuration-vocabulary.md"
+        >
+          {{ this.$t('tagsLink') }}
+        </a>
+        <rk-icon icon="help" class="mr-5" />
+      </span>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+  import { Duration, Option } from '@/types/global';
+  import { Component, Vue } from 'vue-property-decorator';
+  import { Mutation, State } from 'vuex-class';
+
+  @Component({
+    components: {},
+  })
+  export default class LogConditions extends Vue {
+    @State('rocketLog') private rocketLog: any;
+    @Mutation('SET_LOG_CONDITIONS') private SET_LOG_CONDITIONS: any;
+    @Mutation('SET_TAG_LIST') private SET_TAG_LIST: any;
+
+    private tags: string = '';
+    private LogConditionsOpt = {
+      TraceID: 'traceId',
+      Tags: 'tags',
+      KeywordsOfContent: 'keywordsOfContent',
+      ExcludingKeywordsOfContent: 'excludingKeywordsOfContent',
+    };
+    private created() {
+      this.updateTags();
+    }
+    private changeConditions(item: any, type: string) {
+      item = {
+        label: type,
+        key: item.target.value,
+      };
+      this.SET_LOG_CONDITIONS(item);
+    }
+    private addLabels(event: KeyboardEvent) {
+      if (event.keyCode !== 13 || !this.tags) {
+        return;
+      }
+      const tagsList = this.rocketLog.tagsList;
+      tagsList.push(this.tags);
+      this.SET_TAG_LIST(tagsList);
+      this.tags = '';
+      this.updateTags();
+    }
+    private removeTags(index: number) {
+      const tagsList = this.rocketLog.tagsList;
+      tagsList.splice(index, 1);
+      this.SET_TAG_LIST(tagsList);
+      this.updateTags();
+    }
+    private updateTags() {
+      const tagsMap = this.rocketLog.tagsList.map((item: string) => {
+        const key = item.substring(0, item.indexOf('='));
+
+        return {
+          key,
+          value: item.substring(item.indexOf('=') + 1, item.length),
+        };
+      });
+      this.SET_LOG_CONDITIONS({
+        label: this.LogConditionsOpt.Tags,
+        key: tagsMap,
+      });
+      localStorage.setItem('logTags', JSON.stringify(this.rocketLog.tagsList));
+    }
+  }
+</script>
+
+<style scoped lang="scss">
+  .rk-search-conditions {
+    width: 100%;
+    background-color: #484b55;
+    padding: 10px;
+    border-radius: 3px;
+    margin-top: 4px;
+    position: relative;
+    box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1);
+
+    &:after {
+      bottom: 100%;
+      right: 370px;
+      border: solid transparent;
+      content: ' ';
+      height: 0;
+      width: 0;
+      position: absolute;
+      pointer-events: none;
+      border-color: rgba(0, 0, 0, 0);
+      border-bottom-color: #484b55;
+      border-width: 8px;
+      margin-right: 0px;
+    }
+    .rk-log-tag {
+      width: 30%;
+      border-style: unset;
+      outline: 0;
+      border: 1px solid #ccc;
+      height: 30px;
+      padding: 0 5px;
+    }
+    .tags-tips {
+      font-weight: normal;
+    }
+    .remove-icon {
+      display: inline-block;
+      margin-left: 3px;
+      cursor: pointer;
+    }
+    .selected {
+      display: inline-block;
+      padding: 0 3px;
+      border-radius: 3px;
+      overflow: hidden;
+      color: #eee;
+      border: 1px dashed #aaa;
+      font-size: 12px;
+      margin: 0 2px;
+    }
+    .trace-tips {
+      color: #eee;
+    }
+  }
+</style>
diff --git a/src/views/components/log/log-content.vue b/src/views/components/log/log-content.vue
new file mode 100644
index 0000000..4df6217
--- /dev/null
+++ b/src/views/components/log/log-content.vue
@@ -0,0 +1,43 @@
+<!-- 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 class="log-container">
+    <LogServiceDetail :data="logState.logs || []" :loading="logState.loading" v-if="logState.type.key === 'service'" />
+    <LogBrowserDetail :data="logState.logs || []" :loading="logState.loading" v-else />
+  </div>
+</template>
+
+<script lang="ts">
+  import { Duration, Option } from '@/types/global';
+  import { Component, Vue } from 'vue-property-decorator';
+  import { State } from 'vuex-class';
+  import LogBrowserDetail from './log-browser-detail.vue';
+  import LogServiceDetail from './log-service-detail.vue';
+
+  @Component({
+    components: { LogBrowserDetail, LogServiceDetail },
+  })
+  export default class LogContent extends Vue {
+    @State('rocketLog') private logState: any;
+  }
+</script>
+
+<style scoped lang="scss">
+  .log-container {
+    overflow: auto;
+    padding: 5px 15px 15px;
+    height: 100%;
+    flex-grow: 1;
+  }
+</style>
diff --git a/src/views/components/log/log-service-detail.vue b/src/views/components/log/log-service-detail.vue
new file mode 100644
index 0000000..f16c944
--- /dev/null
+++ b/src/views/components/log/log-service-detail.vue
@@ -0,0 +1,124 @@
+<!-- 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 class="log-detail-chart-table">
+    <div class="rk-log-t-loading" v-show="loading">
+      <svg class="icon loading">
+        <use xlink:href="#spinner"></use>
+      </svg>
+    </div>
+    <LogTable :tableData="data" :type="`service`">
+      <div class="log-tips" v-if="!data.length">{{ $t('noData') }}</div>
+    </LogTable>
+    <rk-sidebox :width="'800px'" :show.sync="showDetail" :title="$t('logDetail')">
+      <div class="rk-log-detail">
+        <div class="mb-10 clear rk-flex" v-for="(item, index) in columns" :key="index">
+          <template>
+            <span class="g-sm-4 grey">{{ $t(item.value) }}:</span>
+            <span v-if="item.label === 'timestamp'" class="g-sm-8">{{ currentLog[item.label] | dateformat }}</span>
+            <textarea class="content" readonly="readonly" v-else-if="item.label === 'content'" v-model="logContent" />
+            <span v-else-if="item.label === 'tags'" class="g-sm-8">
+              <div v-for="(d, index) in logTags" :key="index">{{ d }}</div>
+            </span>
+            <span v-else class="g-sm-8">{{ currentLog[item.label] }}</span>
+          </template>
+        </div>
+      </div>
+    </rk-sidebox>
+  </div>
+</template>
+
+<script lang="ts">
+  import { Component, Prop, Vue } from 'vue-property-decorator';
+  import { Mutation, State } from 'vuex-class';
+  import LogTable from './log-table/log-table.vue';
+  import { ServiceLogDetail } from './log-table/log-constant';
+  import { formatJson } from '../../../utils/formatJson';
+
+  @Component({
+    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;
+
+    private columns = ServiceLogDetail;
+    private showDetail = false;
+    private list = [];
+    private currentLog: any = {};
+    private logContent: any = '';
+    private logTags: any = '';
+    private formatJson = formatJson;
+    private created() {
+      this.$eventBus.$on('HANDLE-SELECT-LOG', this, this.handleSelectLog);
+    }
+    private handleSelectLog(data: any) {
+      this.currentLog = data;
+      this.logTags = this.currentLog.tags.map((d: any) => {
+        return `${d.key} = ${d.value}`;
+      });
+      if (this.currentLog.contentType === 'JSON') {
+        this.logContent = formatJson(JSON.parse(this.currentLog.content));
+      } else if (this.currentLog.contentType === 'TEXT') {
+        this.logContent = this.currentLog.content;
+      } else {
+        this.logContent = this.currentLog.content;
+      }
+      if (!this.showBtnDetail) {
+        this.showDetail = true;
+      }
+    }
+  }
+</script>
+<style lang="scss" scoped>
+  .rk-log-t-loading {
+    text-align: center;
+    position: absolute;
+    width: 100%;
+    height: 70px;
+    margin-top: 40px;
+    line-height: 88px;
+    overflow: hidden;
+    .icon {
+      width: 30px;
+      height: 30px;
+    }
+  }
+  .dialog-c-text {
+    white-space: pre;
+    overflow: auto;
+    font-family: monospace;
+  }
+  .log-tips {
+    width: 100%;
+    text-align: center;
+    margin-top: 10px;
+  }
+  .rk-flex {
+    display: flex;
+  }
+  .g-sm-4.grey {
+    flex-shrink: 0;
+  }
+  .content {
+    width: 500px;
+    height: 500px;
+    border: none;
+    outline: none;
+    color: #3d444f;
+  }
+</style>
diff --git a/src/views/components/log/log-table/log-item.vue b/src/views/components/log/log-table/log-browser-item.vue
similarity index 97%
rename from src/views/components/log/log-table/log-item.vue
rename to src/views/components/log/log-table/log-browser-item.vue
index ae7b636..1df1b0b 100644
--- a/src/views/components/log/log-table/log-item.vue
+++ b/src/views/components/log/log-table/log-browser-item.vue
@@ -37,7 +37,7 @@
 
   export default {
     name: 'item',
-    props: ['data', 'type', 'method'],
+    props: ['data', 'method'],
     watch: {
       data: {
         handler() {
@@ -85,7 +85,7 @@
           item.style.background = '#fff';
         }
         this.$refs.logItem.style.background = 'rgba(0, 0, 0, 0.1)';
-        this.$eventBus.$emit('HANDLE-SELECT-SPAN', this.data);
+        this.$eventBus.$emit('HANDLE-SELECT-LOG', this.data);
       },
     },
   };
diff --git a/src/views/components/log/log-table/log-constant.ts b/src/views/components/log/log-table/log-constant.ts
index 1261fc6..c191b77 100644
--- a/src/views/components/log/log-table/log-constant.ts
+++ b/src/views/components/log/log-table/log-constant.ts
@@ -17,8 +17,66 @@
 
 export const ServiceLogConstants = [
   {
-    label: '',
-    value: '',
+    label: 'serviceName',
+    value: 'currentService',
+  },
+  {
+    label: 'serviceInstanceName',
+    value: 'currentInstance',
+  },
+  {
+    label: 'timestamp',
+    value: 'time',
+  },
+  {
+    label: 'contentType',
+    value: 'contentType',
+  },
+  {
+    label: 'isError',
+    value: 'isError',
+  },
+  {
+    label: 'content',
+    value: 'content',
+  },
+  {
+    label: 'traceId',
+    value: 'traceID',
+  },
+];
+export const ServiceLogDetail = [
+  {
+    label: 'serviceName',
+    value: 'currentService',
+  },
+  {
+    label: 'serviceInstanceName',
+    value: 'currentInstance',
+  },
+  {
+    label: 'timestamp',
+    value: 'time',
+  },
+  {
+    label: 'contentType',
+    value: 'contentType',
+  },
+  {
+    label: 'isError',
+    value: 'isError',
+  },
+  {
+    label: 'traceId',
+    value: 'traceID',
+  },
+  {
+    label: 'tags',
+    value: 'tags',
+  },
+  {
+    label: 'content',
+    value: 'content',
   },
 ];
 // The order of columns should be time, service, error, stack, version, url, catalog, and grade.
diff --git a/src/views/components/log/log-table/log-service-item.vue b/src/views/components/log/log-table/log-service-item.vue
new file mode 100644
index 0000000..a24f63f
--- /dev/null
+++ b/src/views/components/log/log-table/log-service-item.vue
@@ -0,0 +1,95 @@
+<!-- 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 @click="showSelectSpan" class="log-item">
+    <div v-for="(item, index) in columns" :key="index" :class="item.label">
+      <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] } }">
+        <span>{{ data[item.label] }}</span>
+      </router-link>
+      <span v-else>{{ data[item.label] }}</span>
+    </div>
+  </div>
+</template>
+<script lang="ts">
+  import { Component, Prop, Vue } from 'vue-property-decorator';
+  import { ServiceLogConstants } from './log-constant';
+
+  @Component
+  export default class ServiceItem extends Vue {
+    @Prop() private data: any;
+    private columns = ServiceLogConstants;
+    private showSelectSpan() {
+      this.$eventBus.$emit('HANDLE-SELECT-LOG', this.data);
+    }
+  }
+</script>
+<style lang="scss" scoped>
+  .log-item {
+    white-space: nowrap;
+    position: relative;
+    cursor: pointer;
+    .traceId {
+      width: 390px;
+      color: #448dfe;
+      cursor: pointer;
+      span {
+        display: inline-block;
+        width: 100%;
+        line-height: 30px;
+      }
+    }
+    .content {
+      width: 300px;
+    }
+    .serviceInstanceName,
+    .serviceName {
+      width: 200px;
+    }
+  }
+
+  .log-item:hover {
+    background: rgba(0, 0, 0, 0.04);
+  }
+
+  .log-item > div {
+    line-height: 1.3;
+    width: 140px;
+    padding: 0 5px;
+    display: inline-block;
+    border: 1px solid transparent;
+    border-right: 1px dotted silver;
+    overflow: hidden;
+    line-height: 30px;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+
+  .log-item .text {
+    width: 100%;
+    display: inline-block;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+
+  .log-item > div.method {
+    height: 100%;
+    padding: 3px 8px;
+  }
+</style>
diff --git a/src/views/components/log/log-table/log-table.vue b/src/views/components/log/log-table/log-table.vue
index 3a526cc..8795e88 100644
--- a/src/views/components/log/log-table/log-table.vue
+++ b/src/views/components/log/log-table/log-table.vue
@@ -19,9 +19,7 @@
       <template v-for="(item, index) in columns">
         <div class="method" :style="`width: ${item.method}px`" v-if="item.drag" :key="index">
           <span class="r cp" ref="dragger" :data-index="index">
-            <svg class="icon">
-              <use xlink:href="#settings_ethernet"></use>
-            </svg>
+            <rk-icon icon="settings_ethernet" />
           </span>
           {{ $t(item.value) }}
         </div>
@@ -30,22 +28,28 @@
         </div>
       </template>
     </div>
-    <Item :method="method" v-for="(item, index) in tableData" :data="item" :key="'key' + index" :type="type" />
+    <div v-if="type === 'browser'">
+      <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" />
+    </div>
     <slot></slot>
   </div>
 </template>
 <script lang="js">
   import { ServiceLogConstants, BrowserLogConstants } from './log-constant';
-  import Item from './log-item';
+  import BrowserItem from './log-browser-item';
+  import ServiceItem from './log-service-item';
 
   export default {
-    components: { Item },
+    components: { ServiceItem, BrowserItem },
     name: 'LogContainer',
     props: ['type', 'tableData'],
     data() {
       return {
         method: 380,
-        columns: BrowserLogConstants,
+        columns: this.type === 'browser' ? BrowserLogConstants : ServiceLogConstants,
       };
     },
     created() {
@@ -61,7 +65,7 @@
       }
     },
     mounted() {
-      const drags = this.$refs.dragger;
+      const drags = this.$refs.dragger || [];
       drags.forEach((drag) => {
         drag.onmousedown = (event) => {
           const diffX = event.clientX;
@@ -100,6 +104,16 @@
     border-right: 0;
     border-bottom: 1px solid rgba(0, 0, 0, 0.1);
     /*background-color: #f3f4f9;*/
+    .traceId {
+      width: 390px;
+    }
+    .content {
+      width: 300px;
+    }
+    .serviceInstanceName,
+    .serviceName {
+      width: 200px;
+    }
   }
 
   .log-header div {
diff --git a/src/views/components/topology/topo-group/index.vue b/src/views/components/topology/topo-group/index.vue
index 6508a67..b55269f 100644
--- a/src/views/components/topology/topo-group/index.vue
+++ b/src/views/components/topology/topo-group/index.vue
@@ -59,7 +59,6 @@
     @Mutation('rocketTopoGroup/INIT_GROUPS') private INIT_GROUPS: any;
     @Mutation('rocketTopoGroup/DELETE_GROUP') private DELETE_GROUP: any;
     @Mutation('rocketTopoGroup/SELECT_GROUP') private SELECT_GROUP: any;
-    @Mutation('SET_EVENTS') private SET_EVENTS: any;
     @Action('rocketTopo/GET_TOPO') private GET_TOPO: any;
     private servicesMap = [];
     private currentPage = 1;
diff --git a/src/views/components/trace/trace-detail-chart-list.vue b/src/views/components/trace/trace-detail-chart-list.vue
index 0d5e7fb..286f4b3 100644
--- a/src/views/components/trace/trace-detail-chart-list.vue
+++ b/src/views/components/trace/trace-detail-chart-list.vue
@@ -85,7 +85,6 @@
         </div>
       </div>
     </rk-sidebox>
-    <v-dialog width="90%" />
     <div class="trace-list">
       <div ref="traceList"></div>
     </div>
diff --git a/src/views/components/trace/trace-detail-chart-tree.vue b/src/views/components/trace/trace-detail-chart-tree.vue
index 046f839..8f0601c 100644
--- a/src/views/components/trace/trace-detail-chart-tree.vue
+++ b/src/views/components/trace/trace-detail-chart-tree.vue
@@ -84,7 +84,6 @@
         </div>
       </div>
     </rk-sidebox>
-    <v-dialog width="90%" />
     <div class="trace-tree" style="height:100%">
       <div class="trace-tree-inner" ref="traceTree"></div>
     </div>
diff --git a/src/views/components/trace/trace-search.vue b/src/views/components/trace/trace-search.vue
index 6976c1c..709ee7b 100644
--- a/src/views/components/trace/trace-search.vue
+++ b/src/views/components/trace/trace-search.vue
@@ -89,21 +89,19 @@
           </span>
           <input
             type="text"
-            :placeholder="this.$t('traceAddTag')"
+            :placeholder="this.$t('addTag')"
             v-model="tags"
             class="rk-trace-new-tag"
             @keyup="addLabels"
           />
-          <span class="trace-tips" v-tooltip:bottom="{ content: this.$t('traceTagsTip') }">
+          <span class="trace-tips" v-tooltip:bottom="{ content: this.$t('tagsTip') }">
             <a
               target="blank"
               href="https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/configuration-vocabulary.md"
             >
-              {{ this.$t('traceLink') }}
+              {{ this.$t('tagsLink') }}
             </a>
-            <svg class="icon mr-5 vm">
-              <use xlink:href="#help"></use>
-            </svg>
+            <rk-icon icon="help" class="mr-5" />
           </span>
         </div>
       </div>
diff --git a/src/views/containers/dashboard.vue b/src/views/containers/dashboard.vue
index 134e694..ecaffbb 100644
--- a/src/views/containers/dashboard.vue
+++ b/src/views/containers/dashboard.vue
@@ -40,7 +40,6 @@
         + Add An Item
       </div>
     </div>
-    <v-dialog width="300px" />
   </div>
 </template>
 
@@ -53,7 +52,7 @@
   import DashboardItem from '@/views/components/dashboard/dashboard-item.vue';
   import { ObjectsType } from '../../constants/constant';
   import { State as globalState } from '@/store/modules/global';
-  import { State as optionState } from '@/store/modules/dashboard/dashboard-option';
+  import { State as optionState } from '@/store/modules/global/selectors';
   import { State as dataState } from '@/store/modules/dashboard/dashboard-data';
 
   interface ITemplate {
diff --git a/src/views/containers/log.vue b/src/views/containers/log.vue
index 6d66473..6c9f360 100644
--- a/src/views/containers/log.vue
+++ b/src/views/containers/log.vue
@@ -12,32 +12,22 @@
 limitations under the License. -->
 <template>
   <div class="flex-v rk-log">
-    <LogBar :logState="logState"></LogBar>
-    <div class="log-container">
-      <LogDetailTable
-        :data="logState.logs"
-        :loading="logState.loading"
-        v-if="logState.type.key === 'browser'"
-      ></LogDetailTable>
-    </div>
+    <LogBar />
+    <LogContent />
   </div>
 </template>
 
 <script lang="ts">
-  import { Component, Vue, Watch } from 'vue-property-decorator';
-  import { Action, Getter, State, Mutation } from 'vuex-class';
+  import { Component, Vue } from 'vue-property-decorator';
   import LogBar from '@/views/components/log/log-bar.vue';
-  import LogDetailTable from '@/views/components/log/log-detail-table.vue';
+  import LogContent from '@/views/components/log/log-content.vue';
   @Component({
     components: {
       LogBar,
-      LogDetailTable,
+      LogContent,
     },
   })
-  export default class Log extends Vue {
-    @Getter('durationTime') private durationTime: any;
-    @State('rocketLog') private logState: any;
-  }
+  export default class Log extends Vue {}
 </script>
 
 <style scoped lang="scss">
@@ -46,10 +36,4 @@
     height: 100%;
     overflow: hidden;
   }
-  .log-container {
-    overflow: auto;
-    padding: 5px 15px 15px;
-    height: 100%;
-    flex-grow: 1;
-  }
 </style>
diff --git a/src/views/containers/topology/alarm/alarm-tool.vue b/src/views/containers/topology/alarm/alarm-tool.vue
index 282ebf9..19dd5d6 100644
--- a/src/views/containers/topology/alarm/alarm-tool.vue
+++ b/src/views/containers/topology/alarm/alarm-tool.vue
@@ -42,7 +42,6 @@
   @Component
   export default class AlarmTool extends Vue {
     @Getter('durationTime') private durationTime: any;
-    @Mutation('SET_EVENTS') private SET_EVENTS: any;
     @Action('rocketAlarm/GET_ALARM') private GET_ALARM: any;
     @Prop() private total!: number;
     @Prop() private keyword!: string;
diff --git a/src/views/containers/topology/endpoint/endpoints-survey.vue b/src/views/containers/topology/endpoint/endpoints-survey.vue
index 6c9551d..c688f5d 100644
--- a/src/views/containers/topology/endpoint/endpoints-survey.vue
+++ b/src/views/containers/topology/endpoint/endpoints-survey.vue
@@ -35,7 +35,7 @@
   import Vue from 'vue';
   import { Component, Prop } from 'vue-property-decorator';
   import { State, Mutation } from 'vuex-class';
-  import { State as optionState } from '@/store/modules/dashboard/dashboard-option';
+  import { State as optionState } from '@/store/modules/global/selectors';
   import DashboardItem from '@/views/components/dashboard/dashboard-item.vue';
 
   @Component({
diff --git a/src/views/containers/topology/instance/instances-survey.vue b/src/views/containers/topology/instance/instances-survey.vue
index 6d99852..029bc83 100644
--- a/src/views/containers/topology/instance/instances-survey.vue
+++ b/src/views/containers/topology/instance/instances-survey.vue
@@ -35,7 +35,7 @@
   import Vue from 'vue';
   import { Component, Prop } from 'vue-property-decorator';
   import { State, Mutation } from 'vuex-class';
-  import { State as optionState } from '@/store/modules/dashboard/dashboard-option';
+  import { State as optionState } from '@/store/modules/global/selectors';
   import DashboardItem from '@/views/components/dashboard/dashboard-item.vue';
 
   @Component({
diff --git a/src/views/containers/trace.vue b/src/views/containers/trace.vue
index e4e10e7..16d7842 100644
--- a/src/views/containers/trace.vue
+++ b/src/views/containers/trace.vue
@@ -45,9 +45,6 @@
     private service!: Option;
 
     @Prop({ default: false, type: Boolean })
-    private inTopo!: boolean;
-
-    private show: boolean = true;
     private beforeMount() {
       this.SET_EVENTS([]);
     }