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, '<')
+ .replace(/>/g, '>')
+ .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, '<')
- .replace(/>/g, '>')
- .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([]);
}