Merge branch 'apache:main' into main

This commit is contained in:
Brandon Fergerson 2022-05-18 19:56:14 +04:00 committed by GitHub
commit cfab1a5ab5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 509 additions and 452 deletions

201
package-lock.json generated
View File

@ -16,7 +16,6 @@
"element-plus": "^2.0.2",
"lodash": "^4.17.21",
"pinia": "^2.0.5",
"vis-timeline": "^7.5.1",
"vue": "^3.0.0",
"vue-grid-layout": "^3.0.0-beta1",
"vue-i18n": "^9.1.9",
@ -1812,18 +1811,6 @@
"ms": "^2.1.1"
}
},
"node_modules/@egjs/hammerjs": {
"version": "2.0.17",
"resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
"integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==",
"peer": true,
"dependencies": {
"@types/hammerjs": "^2.0.36"
},
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/@element-plus/icons-vue": {
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-0.2.7.tgz",
@ -3313,12 +3300,6 @@
"@types/node": "*"
}
},
"node_modules/@types/hammerjs": {
"version": "2.0.41",
"resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.41.tgz",
"integrity": "sha512-ewXv/ceBaJprikMcxCmWU1FKyMAQ2X7a9Gtmzw8fcg2kIePI1crERDM818W+XYrxqdBBOdlf2rm137bU+BltCA==",
"peer": true
},
"node_modules/@types/http-proxy": {
"version": "1.17.8",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz",
@ -7901,7 +7882,8 @@
"node_modules/component-emitter": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
"dev": true
},
"node_modules/compressible": {
"version": "2.0.18",
@ -8713,12 +8695,6 @@
"node": ">=4"
}
},
"node_modules/cssfilter": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
"integrity": "sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4=",
"peer": true
},
"node_modules/cssnano": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz",
@ -16462,12 +16438,6 @@
"node": ">=0.6.0"
}
},
"node_modules/keycharm": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/keycharm/-/keycharm-0.4.0.tgz",
"integrity": "sha512-TyQTtsabOVv3MeOpR92sIKk/br9wxS+zGj4BG7CR8YbK4jM3tyIBaF0zhzeBUMx36/Q/iQLOKKOT+3jOQtemRQ==",
"peer": true
},
"node_modules/killable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
@ -18259,6 +18229,7 @@
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==",
"dev": true,
"engines": {
"node": "*"
}
@ -21727,15 +21698,6 @@
"node": ">= 6"
}
},
"node_modules/propagating-hammerjs": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/propagating-hammerjs/-/propagating-hammerjs-2.0.1.tgz",
"integrity": "sha512-PH3zG5whbSxMocphXJzVtvKr+vWAgfkqVvtuwjSJ/apmEACUoiw6auBAT5HYXpZOR0eGcTAfYG5Yl8h91O5Elg==",
"peer": true,
"peerDependencies": {
"@egjs/hammerjs": "^2.0.17"
}
},
"node_modules/proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@ -26875,6 +26837,7 @@
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true,
"bin": {
"uuid": "dist/bin/uuid"
}
@ -26934,59 +26897,6 @@
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true
},
"node_modules/vis-data": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/vis-data/-/vis-data-7.1.4.tgz",
"integrity": "sha512-usy+ePX1XnArNvJ5BavQod7YRuGQE1pjFl+pu7IS6rCom2EBoG0o1ZzCqf3l5US6MW51kYkLR+efxRbnjxNl7w==",
"hasInstallScript": true,
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/visjs"
},
"peerDependencies": {
"uuid": "^7.0.0 || ^8.0.0",
"vis-util": "^4.0.0 || ^5.0.0"
}
},
"node_modules/vis-timeline": {
"version": "7.5.1",
"resolved": "https://registry.npmjs.org/vis-timeline/-/vis-timeline-7.5.1.tgz",
"integrity": "sha512-XZMHHbA8xm9/Y/iu3mE9MT7J5tfWgbdsW+PmqrgINU2QRX24AiqifNHZHV4YYzeJstiTSOg9Gs5qRkxQ0BvZJw==",
"hasInstallScript": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/visjs"
},
"peerDependencies": {
"@egjs/hammerjs": "^2.0.0",
"component-emitter": "^1.3.0",
"keycharm": "^0.3.0 || ^0.4.0",
"moment": "^2.24.0",
"propagating-hammerjs": "^1.4.0 || ^2.0.0",
"uuid": "^3.4.0 || ^7.0.0 || ^8.0.0",
"vis-data": "^6.3.0 || ^7.0.0",
"vis-util": "^3.0.0 || ^4.0.0 || ^5.0.0",
"xss": "^1.0.0"
}
},
"node_modules/vis-util": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/vis-util/-/vis-util-5.0.3.tgz",
"integrity": "sha512-Wf9STUcFrDzK4/Zr7B6epW2Kvm3ORNWF+WiwEz2dpf5RdWkLUXFSbLcuB88n1W6tCdFwVN+v3V4/Xmn9PeL39g==",
"peer": true,
"engines": {
"node": ">=8"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/visjs"
},
"peerDependencies": {
"@egjs/hammerjs": "^2.0.0",
"component-emitter": "^1.3.0"
}
},
"node_modules/vm-browserify": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
@ -28835,28 +28745,6 @@
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
"dev": true
},
"node_modules/xss": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/xss/-/xss-1.0.11.tgz",
"integrity": "sha512-EimjrjThZeK2MO7WKR9mN5ZC1CSqivSl55wvUK5EtU6acf0rzEE1pN+9ZDrFXJ82BRp3JL38pPE6S4o/rpp1zQ==",
"peer": true,
"dependencies": {
"commander": "^2.20.3",
"cssfilter": "0.0.10"
},
"bin": {
"xss": "bin/xss"
},
"engines": {
"node": ">= 0.10.0"
}
},
"node_modules/xss/node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"peer": true
},
"node_modules/xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
@ -30311,15 +30199,6 @@
}
}
},
"@egjs/hammerjs": {
"version": "2.0.17",
"resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
"integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==",
"peer": true,
"requires": {
"@types/hammerjs": "^2.0.36"
}
},
"@element-plus/icons-vue": {
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-0.2.7.tgz",
@ -31583,12 +31462,6 @@
"@types/node": "*"
}
},
"@types/hammerjs": {
"version": "2.0.41",
"resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.41.tgz",
"integrity": "sha512-ewXv/ceBaJprikMcxCmWU1FKyMAQ2X7a9Gtmzw8fcg2kIePI1crERDM818W+XYrxqdBBOdlf2rm137bU+BltCA==",
"peer": true
},
"@types/http-proxy": {
"version": "1.17.8",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz",
@ -35280,7 +35153,8 @@
"component-emitter": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
"dev": true
},
"compressible": {
"version": "2.0.18",
@ -35921,12 +35795,6 @@
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true
},
"cssfilter": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
"integrity": "sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4=",
"peer": true
},
"cssnano": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz",
@ -42014,12 +41882,6 @@
"verror": "1.10.0"
}
},
"keycharm": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/keycharm/-/keycharm-0.4.0.tgz",
"integrity": "sha512-TyQTtsabOVv3MeOpR92sIKk/br9wxS+zGj4BG7CR8YbK4jM3tyIBaF0zhzeBUMx36/Q/iQLOKKOT+3jOQtemRQ==",
"peer": true
},
"killable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
@ -43406,7 +43268,8 @@
"moment": {
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==",
"dev": true
},
"move-concurrently": {
"version": "1.0.1",
@ -46071,13 +45934,6 @@
"sisteransi": "^1.0.5"
}
},
"propagating-hammerjs": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/propagating-hammerjs/-/propagating-hammerjs-2.0.1.tgz",
"integrity": "sha512-PH3zG5whbSxMocphXJzVtvKr+vWAgfkqVvtuwjSJ/apmEACUoiw6auBAT5HYXpZOR0eGcTAfYG5Yl8h91O5Elg==",
"peer": true,
"requires": {}
},
"proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@ -50179,7 +50035,8 @@
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true
},
"v8-compile-cache": {
"version": "2.3.0",
@ -50228,26 +50085,6 @@
}
}
},
"vis-data": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/vis-data/-/vis-data-7.1.4.tgz",
"integrity": "sha512-usy+ePX1XnArNvJ5BavQod7YRuGQE1pjFl+pu7IS6rCom2EBoG0o1ZzCqf3l5US6MW51kYkLR+efxRbnjxNl7w==",
"peer": true,
"requires": {}
},
"vis-timeline": {
"version": "7.5.1",
"resolved": "https://registry.npmjs.org/vis-timeline/-/vis-timeline-7.5.1.tgz",
"integrity": "sha512-XZMHHbA8xm9/Y/iu3mE9MT7J5tfWgbdsW+PmqrgINU2QRX24AiqifNHZHV4YYzeJstiTSOg9Gs5qRkxQ0BvZJw==",
"requires": {}
},
"vis-util": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/vis-util/-/vis-util-5.0.3.tgz",
"integrity": "sha512-Wf9STUcFrDzK4/Zr7B6epW2Kvm3ORNWF+WiwEz2dpf5RdWkLUXFSbLcuB88n1W6tCdFwVN+v3V4/Xmn9PeL39g==",
"peer": true,
"requires": {}
},
"vm-browserify": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
@ -51759,24 +51596,6 @@
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
"dev": true
},
"xss": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/xss/-/xss-1.0.11.tgz",
"integrity": "sha512-EimjrjThZeK2MO7WKR9mN5ZC1CSqivSl55wvUK5EtU6acf0rzEE1pN+9ZDrFXJ82BRp3JL38pPE6S4o/rpp1zQ==",
"peer": true,
"requires": {
"commander": "^2.20.3",
"cssfilter": "0.0.10"
},
"dependencies": {
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"peer": true
}
}
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",

View File

@ -18,7 +18,6 @@
"element-plus": "^2.0.2",
"lodash": "^4.17.21",
"pinia": "^2.0.5",
"vis-timeline": "^7.5.1",
"vue": "^3.0.0",
"vue-grid-layout": "^3.0.0-beta1",
"vue-i18n": "^9.1.9",

View File

@ -13,7 +13,7 @@ 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>
<router-view :key="$route.fullPath" />
<router-view />
</template>
<style>
#app {

View File

@ -247,7 +247,7 @@ limitations under the License. -->
(state.showMinutes = state.showSeconds = false)
"
:class="{ on: state.showHours }"
>{{ state.hour || dd }}</a
>{{ dd(state.hour) }}</a
>
<span>:</span>
<a
@ -257,7 +257,7 @@ limitations under the License. -->
(state.showHours = state.showSeconds = false)
"
:class="{ on: state.showMinutes }"
>{{ state.minute || dd }}</a
>{{ dd(state.minute) }}</a
>
<span v-show="state.m !== 'D'">
<span>:</span>
@ -268,7 +268,7 @@ limitations under the License. -->
(state.showHours = state.showMinutes = false)
"
:class="{ on: state.showSeconds }"
>{{ state.second || dd }}</a
>{{ dd(state.second) }}</a
>
</span>
</div>
@ -464,7 +464,6 @@ const status = (
const minutes = time.getMinutes();
const seconds = time.getSeconds();
const milliseconds = time.getMilliseconds();
const dd = (t: number) => `0${t}`.slice(-2);
const map: { [key: string]: string | number } = {
YYYY: year,
MM: dd(month + 1),

View File

@ -48,9 +48,9 @@ export const queryEBPFTasks = {
}`,
};
export const queryEBPFSchedules = {
variable: "$taskId: ID!, $duration: Duration!",
variable: "$taskId: ID!",
query: `
eBPFSchedules: queryEBPFProfilingSchedules(taskId: $taskId, duration: $duration) {
eBPFSchedules: queryEBPFProfilingSchedules(taskId: $taskId) {
scheduleId
taskId
process {
@ -60,7 +60,6 @@ export const queryEBPFSchedules = {
serviceName
instanceId
instanceName
layer
agentId
detectType
attributes {

View File

@ -63,3 +63,15 @@ export const QueryLogsByKeywords = {
query: `
support: supportQueryLogsByKeywords`,
};
export const LogTagKeys = {
variable: "$duration: Duration!",
query: `
tagKeys: queryLogTagAutocompleteKeys(duration: $duration)`,
};
export const LogTagValues = {
variable: "$tagKey: String!, $duration: Duration!",
query: `
tagValues: queryLogTagAutocompleteValues(tagKey: $tagKey, duration: $duration)`,
};

View File

@ -20,10 +20,10 @@ export const Services = {
services: listServices(layer: $layer) {
id
value: name
label: name
group
layers
normal
label: name
group
layers
normal
}
`,
};
@ -36,17 +36,16 @@ export const Instances = {
variable: "$serviceId: ID!, $duration: Duration!",
query: `
pods: listInstances(duration: $duration, serviceId: $serviceId) {
id
value: name
label: name
language
instanceUUID
layer
attributes {
name
value
}
id
value: name
label: name
language
instanceUUID
attributes {
name
value
}
}
`,
};
export const Endpoints = {
@ -66,10 +65,10 @@ export const getService = {
service: getService(serviceId: $serviceId) {
id
value: name
label: name
group
layers
normal
label: name
group
layers
normal
}
`,
};
@ -79,16 +78,15 @@ export const getInstance = {
query: `
instance: getInstance(instanceId: $instanceId) {
id
value: name
label: name
language
instanceUUID
layer
attributes {
name
value
}
value: name
label: name
language
instanceUUID
attributes {
name
value
}
}
`,
};
@ -97,10 +95,10 @@ export const getEndpoint = {
query: `
endpoint: getEndpointInfo(endpointId: $endpointId) {
id
value: name
label: name
serviceId
serviceName
value: name
label: name
serviceId
serviceName
}
`,
};

View File

@ -74,3 +74,14 @@ export const TraceSpans = {
}
`,
};
export const TraceTagKeys = {
variable: "$duration: Duration!",
query: `
tagKeys: queryTraceTagAutocompleteKeys(duration: $duration)`,
};
export const TraceTagValues = {
variable: "$tagKey: String!, $duration: Duration!",
query: `
tagValues: queryTraceTagAutocompleteValues(tagKey: $tagKey, duration: $duration)`,
};

View File

@ -19,9 +19,13 @@ import {
QueryBrowserErrorLogs,
QueryServiceLogs,
QueryLogsByKeywords,
LogTagValues,
LogTagKeys,
} 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}}`;
export const queryLogTagValues = `query queryTagValues(${LogTagValues.variable}) {${LogTagValues.query}}`;
export const queryLogTagKeys = `query queryTagKeys(${LogTagKeys.variable}) {${LogTagKeys.query}}`;

View File

@ -15,8 +15,17 @@
* limitations under the License.
*/
import { Traces, TraceSpans } from "../fragments/trace";
import {
Traces,
TraceSpans,
TraceTagKeys,
TraceTagValues,
} from "../fragments/trace";
export const queryTraces = `query queryTraces(${Traces.variable}) {${Traces.query}}`;
export const queryTrace = `query queryTrace(${TraceSpans.variable}) {${TraceSpans.query}}`;
export const queryTraceTagKeys = `query queryTraceTagKeys(${TraceTagKeys.variable}) {${TraceTagKeys.query}}`;
export const queryTraceTagValues = `query queryTraceTagValues(${TraceTagValues.variable}) {${TraceTagValues.query}}`;

View File

@ -331,7 +331,7 @@ export function useQueryTopologyMetrics(metrics: string[], ids: string[]) {
}
function calculateExp(
arr: { value: number }[],
config: { calculation: string }
config: { calculation?: string }
): (number | string)[] {
const sum = arr
.map((d: { value: number }) => d.value)
@ -356,7 +356,7 @@ function calculateExp(
export function aggregation(
val: number,
config: { calculation: string }
config: { calculation?: string }
): number | string {
let data: number | string = Number(val);

View File

@ -21,19 +21,6 @@ limitations under the License. -->
</router-view>
</section>
</template>
<script lang="ts" setup>
import { ElMessage } from "element-plus";
import { useAppStoreWithOut } from "@/store/modules/app";
const appStore = useAppStoreWithOut();
if (!appStore.utc) {
const res = appStore.queryOAPTimeInfo();
if (res.errors) {
ElMessage.error(res.errors);
}
}
</script>
<style lang="scss" scoped>
.app-main {
height: calc(100% - 40px);

View File

@ -94,9 +94,6 @@ watch(
}
);
async function getVersion() {
if (appStore.version) {
return;
}
const res = await appStore.fetchVersion();
if (res.errors) {
ElMessage.error(res.errors);

View File

@ -113,11 +113,11 @@ import { useAppStoreWithOut } from "@/store/modules/app";
const appStore = useAppStoreWithOut();
const { t } = useI18n();
const name = ref<any>(String(useRouter().currentRoute.value.name));
const name = ref<string>(String(useRouter().currentRoute.value.name));
const theme = ["VirtualMachine", "Kubernetes"].includes(name.value || "")
? ref("light")
: ref("black");
const routes = ref<any>(useRouter().options.routes);
const routes = ref<RouteRecordRaw[] | any>(useRouter().options.routes);
if (/Android|webOS|iPhone|iPod|iPad|BlackBerry/i.test(navigator.userAgent)) {
appStore.setIsMobile(true);
} else {

View File

@ -134,7 +134,7 @@ const msg = {
taskId: "Task ID",
triggerType: "Trigger Type",
targetType: "Target Type",
ebpfTip: "Don't have process could profiling",
ebpfTip: "Don't have a process for profiling",
processSelect: "Click to select processes",
hourTip: "Select Hour",
minuteTip: "Select Minute",
@ -326,7 +326,7 @@ const msg = {
addExcludingKeywordsOfContent: "Please input a keyword of excluding content",
noticeTag: "Please press Enter after inputting a tag(key=value).",
conditionNotice:
"Notice: Please press Enter after inputting a tag, key of content, exclude key of content(key=value).",
"Notice: Please press Enter after inputting a key of content, exclude key of content(key=value).",
language: "Language",
};
export default msg;

View File

@ -327,7 +327,7 @@ const msg = {
addExcludingKeywordsOfContent: "请输入一个内容不包含的关键词",
noticeTag: "请输入一个标签(key=value)之后回车",
conditionNotice:
"请输入一个标签、内容关键词或者内容不包含的关键词(key=value)之后回车",
"请输入一个内容关键词或者内容不包含的关键词(key=value)之后回车",
language: "语言",
};
export default msg;

View File

@ -20,11 +20,18 @@ import router from "./router";
import { store } from "./store";
import components from "@/components";
import i18n from "./locales";
import { useAppStoreWithOut } from "@/store/modules/app";
import "./styles/index.ts";
const app = createApp(App);
const appStore = useAppStoreWithOut();
app.use(components);
app.use(i18n);
app.use(store);
app.use(router).mount("#app");
mountApp();
async function mountApp() {
await appStore.queryOAPTimeInfo();
app.use(router).mount("#app");
}

View File

@ -20,10 +20,8 @@ import { LayoutConfig } from "@/types/dashboard";
import graphql from "@/graphql";
import query from "@/graphql/fetch";
import { DashboardItem } from "@/types/dashboard";
import { useAppStoreWithOut } from "@/store/modules/app";
import { useSelectorStore } from "@/store/modules/selectors";
import { NewControl, TextConfig } from "../data";
import { Duration } from "@/types/app";
import { AxiosResponse } from "axios";
import { ElMessage } from "element-plus";
import { useI18n } from "vue-i18n";
@ -35,7 +33,6 @@ interface DashboardState {
entity: string;
layerId: string;
activedGridItem: string;
durationTime: Duration;
selectorStore: any;
showTopology: boolean;
currentTabItems: LayoutConfig[];
@ -53,7 +50,6 @@ export const dashboardStore = defineStore({
entity: "",
layerId: "",
activedGridItem: "",
durationTime: useAppStoreWithOut().durationTime,
selectorStore: useSelectorStore(),
showTopology: false,
currentTabItems: [],

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { defineStore } from "pinia";
import { Duration, Option } from "@/types/app";
import { Option } from "@/types/app";
import {
EBPFTaskCreationRequest,
EBPFProfilingSchedule,
@ -26,10 +26,8 @@ import { Trace, Span } from "@/types/trace";
import { store } from "@/store";
import graphql from "@/graphql";
import { AxiosResponse } from "axios";
import { useAppStoreWithOut } from "@/store/modules/app";
interface EbpfStore {
durationTime: Duration;
taskList: EBPFTaskList[];
eBPFSchedules: EBPFProfilingSchedule[];
currentSchedule: EBPFProfilingSchedule | Record<string, never>;
@ -42,7 +40,6 @@ interface EbpfStore {
export const ebpfStore = defineStore({
id: "eBPF",
state: (): EbpfStore => ({
durationTime: useAppStoreWithOut().durationTime,
taskList: [],
eBPFSchedules: [],
currentSchedule: {},
@ -103,14 +100,13 @@ export const ebpfStore = defineStore({
this.getEBPFSchedules({ taskId: this.taskList[0].taskId });
return res.data;
},
async getEBPFSchedules(params: { taskId: string; duration?: Duration }) {
async getEBPFSchedules(params: { taskId: string }) {
if (!params.taskId) {
return new Promise((resolve) => resolve({}));
}
const duration = useAppStoreWithOut().durationTime;
const res: AxiosResponse = await graphql
.query("getEBPFSchedules")
.params({ ...params, duration });
.params({ ...params });
if (res.data.errors) {
this.eBPFSchedules = [];
@ -154,7 +150,7 @@ export const ebpfStore = defineStore({
this.analyzeTrees = [];
return res.data;
}
this.analyzeTrees = analysisEBPFResult.trees[0].elements;
this.analyzeTrees = analysisEBPFResult.trees;
return res.data;
},
},

View File

@ -42,7 +42,6 @@ export const eventStore = defineStore({
instances: [{ value: "", label: "All" }],
endpoints: [{ value: "", label: "All" }],
condition: {
time: useAppStoreWithOut().durationTime,
paging: { pageNum: 1, pageSize: 15, needTotal: true },
},
}),
@ -94,9 +93,12 @@ export const eventStore = defineStore({
},
async getEvents() {
this.loading = true;
const res: AxiosResponse = await graphql
.query("queryEvents")
.params({ condition: this.condition });
const res: AxiosResponse = await graphql.query("queryEvents").params({
condition: {
...this.condition,
time: useAppStoreWithOut().durationTime,
},
});
this.loading = false;
if (res.data.errors) {
return res.data;

View File

@ -15,7 +15,6 @@
* limitations under the License.
*/
import { defineStore } from "pinia";
import { Duration } from "@/types/app";
import { Instance, Endpoint, Service } from "@/types/selector";
import { store } from "@/store";
import graphql from "@/graphql";
@ -29,7 +28,6 @@ interface LogState {
instances: Instance[];
endpoints: Endpoint[];
conditions: any;
durationTime: Duration;
selectorStore: any;
supportQueryLogsByKeywords: boolean;
logs: any[];
@ -48,7 +46,6 @@ export const logStore = defineStore({
paging: { pageNum: 1, pageSize: 15, needTotal: true },
},
supportQueryLogsByKeywords: true,
durationTime: useAppStoreWithOut().durationTime,
selectorStore: useSelectorStore(),
logs: [],
logsTotal: 0,
@ -74,7 +71,7 @@ export const logStore = defineStore({
: id;
const res: AxiosResponse = await graphql.query("queryInstances").params({
serviceId,
duration: this.durationTime,
duration: useAppStoreWithOut().durationTime,
});
if (res.data.errors) {
@ -92,7 +89,7 @@ export const logStore = defineStore({
: id;
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
serviceId,
duration: this.durationTime,
duration: useAppStoreWithOut().durationTime,
keyword: keyword || "",
});
if (res.data.errors) {
@ -151,6 +148,20 @@ export const logStore = defineStore({
this.logsTotal = res.data.data.queryBrowserErrorLogs.total;
return res.data;
},
async getLogTagKeys() {
const res: AxiosResponse = await graphql
.query("queryLogTagKeys")
.params({ duration: useAppStoreWithOut().durationTime });
return res.data;
},
async getLogTagValues(tagKey: string) {
const res: AxiosResponse = await graphql
.query("queryLogTagValues")
.params({ tagKey, duration: useAppStoreWithOut().durationTime });
return res.data;
},
},
});

View File

@ -15,7 +15,6 @@
* limitations under the License.
*/
import { defineStore } from "pinia";
import { Duration } from "@/types/app";
import { Endpoint } from "@/types/selector";
import {
TaskListItem,
@ -33,7 +32,6 @@ import { useAppStoreWithOut } from "@/store/modules/app";
interface ProfileState {
endpoints: Endpoint[];
taskEndpoints: Endpoint[];
durationTime: Duration;
condition: { serviceId: string; endpointName: string };
taskList: TaskListItem[];
segmentList: Trace[];
@ -50,7 +48,6 @@ export const profileStore = defineStore({
state: (): ProfileState => ({
endpoints: [{ value: "", label: "All" }],
taskEndpoints: [{ value: "", label: "All" }],
durationTime: useAppStoreWithOut().durationTime,
condition: { serviceId: "", endpointName: "" },
taskList: [],
segmentList: [],
@ -80,7 +77,7 @@ export const profileStore = defineStore({
async getEndpoints(serviceId: string, keyword?: string) {
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
serviceId,
duration: this.durationTime,
duration: useAppStoreWithOut().durationTime,
keyword: keyword || "",
});
if (res.data.errors) {
@ -92,7 +89,7 @@ export const profileStore = defineStore({
async getTaskEndpoints(serviceId: string, keyword?: string) {
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
serviceId,
duration: this.durationTime,
duration: useAppStoreWithOut().durationTime,
keyword: keyword || "",
});
if (res.data.errors) {

View File

@ -15,13 +15,11 @@
* limitations under the License.
*/
import { defineStore } from "pinia";
import { Duration } from "@/types/app";
import { Service, Instance, Endpoint } from "@/types/selector";
import { store } from "@/store";
import graphql from "@/graphql";
import { AxiosResponse } from "axios";
import { useAppStoreWithOut } from "@/store/modules/app";
interface SelectorState {
services: Service[];
destServices: Service[];
@ -31,7 +29,6 @@ interface SelectorState {
currentDestService: Nullable<Service>;
currentDestPod: Nullable<Instance | Endpoint>;
destPods: Array<Instance | Endpoint>;
durationTime: Duration;
}
export const selectorStore = defineStore({
@ -45,7 +42,6 @@ export const selectorStore = defineStore({
currentPod: null,
currentDestService: null,
currentDestPod: null,
durationTime: useAppStoreWithOut().durationTime,
}),
actions: {
setCurrentService(service: Nullable<Service>) {
@ -86,7 +82,7 @@ export const selectorStore = defineStore({
}
const res: AxiosResponse = await graphql.query("queryInstances").params({
serviceId,
duration: this.durationTime,
duration: useAppStoreWithOut().durationTime,
});
if (!res.data.errors) {
if (param && param.isRelation) {
@ -112,7 +108,7 @@ export const selectorStore = defineStore({
}
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
serviceId,
duration: this.durationTime,
duration: useAppStoreWithOut().durationTime,
keyword: params.keyword || "",
limit: params.limit,
});

View File

@ -15,7 +15,6 @@
* limitations under the License.
*/
import { defineStore } from "pinia";
import { Duration } from "@/types/app";
import { Instance, Endpoint, Service } from "@/types/selector";
import { Trace, Span } from "@/types/trace";
import { store } from "@/store";
@ -35,10 +34,6 @@ interface TraceState {
conditions: any;
traceSpanLogs: any[];
traceSpanLogsTotal: number;
// traceListErrors: string;
// traceSpanErrors: string;
// traceSpanLogErrors: string;
durationTime: Duration;
selectorStore: any;
}
@ -60,12 +55,11 @@ export const traceStore = defineStore({
},
traceSpanLogs: [],
traceSpanLogsTotal: 0,
durationTime: useAppStoreWithOut().durationTime,
selectorStore: useSelectorStore(),
}),
actions: {
setTraceCondition(data: any) {
this.condition = { ...this.condition, ...data };
this.conditions = { ...this.conditions, ...data };
},
setCurrentTrace(trace: Trace) {
this.currentTrace = trace;
@ -89,7 +83,7 @@ export const traceStore = defineStore({
: id;
const res: AxiosResponse = await graphql.query("queryInstances").params({
serviceId: serviceId,
duration: this.durationTime,
duration: useAppStoreWithOut().durationTime,
});
if (res.data.errors) {
@ -104,7 +98,7 @@ export const traceStore = defineStore({
: id;
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
serviceId,
duration: this.durationTime,
duration: useAppStoreWithOut().durationTime,
keyword: keyword || "",
});
if (res.data.errors) {
@ -116,7 +110,7 @@ export const traceStore = defineStore({
async getTraces() {
const res: AxiosResponse = await graphql
.query("queryTraces")
.params({ condition: this.condition });
.params({ condition: this.conditions });
if (res.data.errors) {
return res.data;
}
@ -161,6 +155,20 @@ export const traceStore = defineStore({
this.traceSpanLogsTotal = res.data.data.queryLogs.total;
return res.data;
},
async getTagKeys() {
const res: AxiosResponse = await graphql
.query("queryTraceTagKeys")
.params({ duration: useAppStoreWithOut().durationTime });
return res.data;
},
async getTagValues(tagKey: string) {
const res: AxiosResponse = await graphql
.query("queryTraceTagValues")
.params({ tagKey, duration: useAppStoreWithOut().durationTime });
return res.data;
},
},
});

View File

@ -39,9 +39,9 @@ export interface LayoutConfig {
}
export type MetricConfigOpt = {
unit: string;
label: string;
calculation: string;
unit?: string;
label?: string;
calculation?: string;
labelsIndex: string;
sortOrder: string;
topN?: number;

3
src/types/ebpf.d.ts vendored
View File

@ -50,10 +50,9 @@ export type Process = {
serviceName: string;
instanceId: string;
instanceName: string;
layer: string;
agentId: string;
detectType: string;
attributes: { name: string; value: string };
attributes: { name: string; value: string }[];
labels: string[];
};
export type StackElement = {

View File

@ -26,7 +26,6 @@ export type Service = {
export type Instance = {
value: string;
label: string;
layer?: string;
language?: string;
instanceUUID?: string;
attributes?: { name: string; value: string }[];

View File

@ -13,65 +13,99 @@ 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="flex-h" :class="{ light: theme === 'light' }">
<div class="mr-5">
<span class="sm grey" v-show="theme === 'dark'">{{ t("tags") }}: </span>
<span
class="trace-tags"
:style="type === 'LOG' ? `min-width: 122px;` : ''"
>
<span class="selected" v-for="(item, index) in tagsList" :key="index">
<span>{{ item }}</span>
<span class="remove-icon" @click="removeTags(index)">×</span>
</span>
<div>
<span class="grey">{{ t("tags") }}: </span>
<span
v-if="tagsList.length"
class="trace-tags"
:style="type === 'LOG' ? `min-width: 122px;` : ''"
>
<span class="selected" v-for="(item, index) in tagsList" :key="index">
<span>{{ item }}</span>
<span class="remove-icon" @click="removeTags(index)">×</span>
</span>
</span>
<el-input
v-if="type === 'ALARM'"
size="small"
v-model="tags"
class="trace-new-tag"
@change="addLabels"
:placeholder="t('addTags')"
/>
<span v-else>
<el-input
size="small"
v-model="tags"
class="trace-new-tag"
@change="addLabels"
:placeholder="t('addTags')"
@click="showClick"
/>
<span class="tags-tip">
<a
target="blank"
href="https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/configuration-vocabulary.md"
>
{{ t("tagsLink") }}
</a>
<el-tooltip
:content="
t(
type === 'LOG'
? 'logTagsTip'
: type === 'TRACE'
? 'traceTagsTip'
: 'alarmTagsTip'
)
"
>
<span>
<Icon class="icon-help mr-5" iconName="help" size="middle" />
</span>
</el-tooltip>
<b v-if="type !== 'LOG'">{{ t("noticeTag") }}</b>
</span>
</div>
<el-dropdown
ref="dropdownTag"
trigger="contextmenu"
:hide-on-click="false"
style="margin: 20px 0 0 -130px"
v-if="tagArr.length"
>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="(item, index) in tagArr" :key="index">
<span @click="selectTag(item)" class="tag-item">
{{ item }}
</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</span>
<span
class="tags-tip"
:class="type !== 'ALARM' && tagArr.length ? 'link-tips' : ''"
>
<a
target="blank"
href="https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/configuration-vocabulary.md"
>
{{ t("tagsLink") }}
</a>
<el-tooltip :content="t(tipsMap[type])">
<span>
<Icon class="icon-help mr-5" iconName="help" size="middle" />
</span>
</el-tooltip>
<b v-if="type === 'AL'">{{ t("noticeTag") }}</b>
</span>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { ref, watch } from "vue";
import { useI18n } from "vue-i18n";
import { useTraceStore } from "@/store/modules/trace";
import { useLogStore } from "@/store/modules/log";
import { ElMessage } from "element-plus";
import { useAppStoreWithOut } from "@/store/modules/app";
/*global defineEmits, defineProps */
/*global Nullable, defineEmits, defineProps */
const emit = defineEmits(["update"]);
defineProps({
const props = defineProps({
type: { type: String, default: "TRACE" },
});
const traceStore = useTraceStore();
const logStore = useLogStore();
const appStore = useAppStoreWithOut();
const { t } = useI18n();
const theme = ref<string>("dark");
const tags = ref<string>("");
const tagsList = ref<string[]>([]);
const tagArr = ref<string[]>([]);
const tagKeys = ref<string[]>([]);
const tipsMap = {
LOG: "logTagsTip",
TRACE: "traceTagsTip",
ALARM: "alarmTagsTip",
};
const dropdownTag = ref<Nullable<any>>(null);
fetchTagKeys();
function removeTags(index: number) {
tagsList.value.splice(index, 1);
@ -95,6 +129,61 @@ function updateTags() {
});
emit("update", { tagsMap, tagsList: tagsList.value });
}
async function fetchTagKeys() {
let resp: any = {};
if (props.type === "TRACE") {
resp = await traceStore.getTagKeys();
} else {
resp = await logStore.getLogTagKeys();
}
if (resp.errors) {
ElMessage.error(resp.errors);
return;
}
tagArr.value = resp.data.tagKeys;
tagKeys.value = resp.data.tagKeys;
}
async function fetchTagValues() {
const param = tags.value.split("=")[0];
let resp: any = {};
if (props.type === "TRACE") {
resp = await traceStore.getTagValues(param);
} else {
resp = await logStore.getLogTagValues(param);
}
if (resp.errors) {
ElMessage.error(resp.errors);
return;
}
tagArr.value = resp.data.tagValues;
}
function selectTag(item: string) {
if (tags.value.includes("=")) {
tags.value += item;
addLabels();
tagArr.value = tagKeys.value;
dropdownTag.value.handleClose();
return;
}
tags.value = item + "=";
fetchTagValues();
}
function showClick() {
if (dropdownTag.value) {
dropdownTag.value.handleOpen();
}
}
watch(
() => appStore.durationTime,
() => {
fetchTagKeys();
}
);
</script>
<style lang="scss" scoped>
.trace-tags {
@ -121,7 +210,6 @@ function updateTags() {
padding: 2px 5px;
border-radius: 3px;
width: 250px;
margin-right: 3px;
}
.remove-icon {
@ -130,10 +218,20 @@ function updateTags() {
cursor: pointer;
}
.tag-item {
display: inline-block;
min-width: 210px;
}
.tags-tip {
color: #a7aebb;
}
.link-tips {
display: inline-block;
margin-left: 130px;
}
.light {
color: #3d444f;

View File

@ -146,9 +146,10 @@ import type { ElTable } from "element-plus";
import { useAppStoreWithOut } from "@/store/modules/app";
import { useDashboardStore } from "@/store/modules/dashboard";
import router from "@/router";
import { DashboardItem } from "@/types/dashboard";
import { DashboardItem, LayoutConfig } from "@/types/dashboard";
import { saveFile, readFile } from "@/utils/file";
import { EntityType } from "./data";
import { isEmptyObject } from "@/utils/is";
/*global Nullable*/
const { t } = useI18n();
@ -221,12 +222,77 @@ function exportTemplates() {
const layout = JSON.parse(sessionStorage.getItem(key) || "{}");
return layout;
});
for (const item of templates) {
optimizeTemplate(item.configuration.children);
}
const name = `dashboards.json`;
saveFile(templates, name);
setTimeout(() => {
multipleTableRef.value!.clearSelection();
}, 2000);
}
function optimizeTemplate(
children: (LayoutConfig & { moved?: boolean; standard?: unknown })[]
) {
for (const child of children || []) {
delete child.moved;
delete child.activedTabIndex;
delete child.standard;
if (isEmptyObject(child.graph)) {
delete child.graph;
}
if (child.widget) {
if (child.widget.title === "") {
delete child.widget.title;
}
if (child.widget.tips === "") {
delete child.widget.tips;
}
}
if (isEmptyObject(child.widget)) {
delete child.widget;
}
if (!(child.metrics && child.metrics.length && child.metrics[0])) {
delete child.metrics;
}
if (
!(child.metricTypes && child.metricTypes.length && child.metricTypes[0])
) {
delete child.metricTypes;
}
if (child.metricConfig && child.metricConfig.length) {
child.metricConfig.forEach((c, index) => {
if (!c.calculation) {
delete c.calculation;
}
if (!c.unit) {
delete c.unit;
}
if (!c.label) {
delete c.label;
}
if (isEmptyObject(c)) {
(child.metricConfig || []).splice(index, 1);
}
});
}
if (!(child.metricConfig && child.metricConfig.length)) {
delete child.metricConfig;
}
if (child.type === "Tab") {
for (const item of child.children || []) {
optimizeTemplate(item.children);
}
}
if (
["Trace", "Topology", "Tab", "Profile", "Ebpf", "Log"].includes(
child.type
)
) {
delete child.widget;
}
}
}
function handleEdit(row: DashboardItem) {
dashboardStore.setMode(true);
dashboardStore.setEntity(row.entity);

View File

@ -16,7 +16,7 @@ limitations under the License. -->
<div class="flex-h content">
<TaskList />
<div class="vis-graph ml-5">
<div class="item">
<div class="schedules">
<EBPFSchedules />
</div>
<div class="item">
@ -39,12 +39,18 @@ import EBPFStack from "./components/EBPFStack.vue";
.vis-graph {
height: 100%;
width: calc(100% - 300px);
min-width: 700px;
overflow: auto;
}
.item {
width: 100%;
overflow: auto;
height: calc(50% - 10px);
height: calc(100% - 70px);
padding-bottom: 10px;
}
.schedules {
height: 60px;
}
</style>

View File

@ -13,7 +13,7 @@ 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="filters">
<div class="filters flex-h">
<Selector
:value="selectedLabels"
:options="labels"
@ -23,6 +23,11 @@ limitations under the License. -->
class="inputs mr-10"
:multiple="true"
/>
<el-button type="primary" size="small">
<span>{{ duration[0] }}</span>
<span> ~ </span>
<span>{{ duration[1] }}</span>
</el-button>
<el-popover placement="bottom" :width="680" trigger="click">
<template #reference>
<el-button type="primary" size="small">
@ -34,7 +39,7 @@ limitations under the License. -->
placeholder="Please input name"
class="input-with-search"
size="small"
@change="searchProcesses"
@change="searchProcesses(0)"
>
<template #append>
<el-button size="small">
@ -77,7 +82,6 @@ limitations under the License. -->
{{ t("analyze") }}
</el-button>
</div>
<div ref="timeline" class="schedules"></div>
</template>
<script lang="ts" setup>
import { ref, watch } from "vue";
@ -87,25 +91,21 @@ import { Option } from "@/types/app";
import { TableHeader } from "./data";
import { useEbpfStore } from "@/store/modules/ebpf";
import { EBPFProfilingSchedule, Process } from "@/types/ebpf";
import { DataSet, Timeline } from "vis-timeline/standalone";
import "vis-timeline/styles/vis-timeline-graph2d.css";
import { ElMessage, ElTable } from "element-plus";
const { t } = useI18n();
const ebpfStore = useEbpfStore();
const pageSize = 5;
/*global Nullable */
const multipleTableRef = ref<InstanceType<typeof ElTable>>();
const selectedProcesses = ref<string[]>([]);
const timeline = ref<Nullable<HTMLDivElement>>(null);
const visGraph = ref<Nullable<any>>(null);
const labels = ref<Option[]>([{ label: "All", value: "0" }]);
const processes = ref<Process[]>([]);
const currentProcesses = ref<Process[]>([]);
const selectedLabels = ref<string[]>(["0"]);
const searchText = ref<string>("");
const duration = ref<string[]>([]);
const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") =>
new Date(dayjs(date).format(pattern));
dayjs(date).format(pattern);
function changeLabels(opt: any[]) {
const arr = opt.map((d) => d.value);
@ -160,56 +160,59 @@ async function analyzeEBPF() {
}
function visTimeline() {
if (visGraph.value) {
visGraph.value.destroy();
}
labels.value = [{ label: "All", value: "0" }];
selectedLabels.value = ["0"];
processes.value = [];
const schedules = ebpfStore.eBPFSchedules.map(
(d: EBPFProfilingSchedule, index: number) => {
for (const l of d.process.labels) {
labels.value.push({ label: l, value: l });
}
processes.value.push(d.process);
return {
id: index + 1,
content: d.process.name,
start: dateFormat(d.startTime),
end: dateFormat(d.endTime),
};
const ranges = ebpfStore.eBPFSchedules.map((d: EBPFProfilingSchedule) => {
for (const l of d.process.labels) {
labels.value.push({ label: l, value: l });
}
);
searchProcesses();
if (!timeline.value) {
return;
}
const h = timeline.value.getBoundingClientRect().height;
const items: any = new DataSet(schedules);
const options = {
height: h,
width: "100%",
locale: "en",
};
visGraph.value = new Timeline(timeline.value, items, options);
processes.value.push(d.process);
return [d.startTime / 10000, d.endTime / 10000];
});
const arr = ranges.flat(1);
const min = Math.min(...arr);
const max = Math.max(...arr);
duration.value = [dateFormat(min * 10000), dateFormat(max * 10000)];
searchProcesses(0);
}
function changePage(pageIndex: number) {
searchProcesses(pageIndex);
}
function searchProcesses(pageIndex?: any) {
function searchProcesses(pageIndex: number) {
const arr = processes.value.filter(
(d: { name: string; instanceName: string }) =>
(d: {
name: string;
instanceName: string;
attributes: { name: string; value: string }[];
}) =>
d.name.includes(searchText.value) ||
d.instanceName.includes(searchText.value)
d.instanceName.includes(searchText.value) ||
searchAttribute(d.attributes, searchText.value)
);
currentProcesses.value = arr.splice(
(pageIndex - 1 || 0) * pageSize,
pageSize * (pageIndex || 1)
currentProcesses.value = arr.filter(
(d, index: number) =>
(pageIndex - 1 || 0) * pageSize <= index &&
pageSize * (pageIndex || 1) > index
);
}
function searchAttribute(
attributes: { name: string; value: string }[],
text: string
) {
const item = attributes.find(
(d: { name: string; value: string }) => d.name === "command_line"
);
if (!item) {
return false;
}
return item.value.includes(text);
}
watch(
() => ebpfStore.eBPFSchedules,
() => {

View File

@ -31,6 +31,8 @@ const ebpfStore = useEbpfStore();
const stackTree = ref<Nullable<StackElement>>(null);
const graph = ref<Nullable<HTMLDivElement>>(null);
const flameChart = ref<any>(null);
const min = ref<number>(1);
const max = ref<number>(1);
function drawGraph() {
if (flameChart.value) {
@ -39,8 +41,33 @@ function drawGraph() {
if (!ebpfStore.analyzeTrees.length) {
return (stackTree.value = null);
}
stackTree.value = processTree(ebpfStore.analyzeTrees);
const root: StackElement = {
parentId: "0",
originId: "1",
name: "Virtual Root",
children: [],
value: 0,
id: "1",
symbol: "Virtual Root",
dumpCount: 0,
stackType: "",
};
countRange();
for (const tree of ebpfStore.analyzeTrees) {
const ele = processTree(tree.elements);
root.children && root.children.push(ele);
}
const param = (root.children || []).reduce(
(prev: number[], curr: StackElement) => {
prev[0] += curr.value;
prev[1] += curr.dumpCount;
return prev;
},
[0, 0]
);
root.value = param[0];
root.dumpCount = param[1];
stackTree.value = root;
const w = (graph.value && graph.value.getBoundingClientRect().width) || 10;
flameChart.value = flamegraph()
.width(w - 15)
@ -51,6 +78,7 @@ function drawGraph() {
.sort(true)
.title("")
.selfValue(false)
.inverted(true)
.setColorMapper((d, originalColor) =>
d.highlight ? "#6aff8f" : originalColor
);
@ -59,33 +87,38 @@ function drawGraph() {
.direction("w")
.html(
(d: { data: StackElement }) =>
`<div class="mb-5">Symbol: ${d.data.name}</div><div class="mb-5">Dump Count: ${d.data.dumpCount}</div>`
);
`<div class="mb-5 name">Symbol: ${d.data.name}</div><div class="mb-5">Dump Count: ${d.data.dumpCount}</div>`
)
.style("max-width", "500px");
flameChart.value.tooltip(tip);
d3.select("#graph-stack").datum(stackTree.value).call(flameChart.value);
}
function countRange() {
const list = [];
for (const tree of ebpfStore.analyzeTrees) {
for (const ele of tree.elements) {
list.push(ele.dumpCount);
}
}
max.value = Math.max(...list);
min.value = Math.min(...list);
}
function processTree(arr: StackElement[]) {
const copyArr = JSON.parse(JSON.stringify(arr));
const copyArr = (window as any).structuredClone(arr);
const obj: any = {};
let res = null;
let min = 1;
let max = 1;
for (const item of copyArr) {
item.originId = item.id;
item.parentId = String(Number(item.parentId) + 1);
item.originId = String(Number(item.id) + 1);
item.name = item.symbol;
delete item.id;
obj[item.originId] = item;
if (item.dumpCount > max) {
max = item.dumpCount;
}
if (item.dumpCount < min) {
min = item.dumpCount;
}
}
const scale = d3.scaleLinear().domain([min, max]).range([1, 200]);
const scale = d3.scaleLinear().domain([min.value, max.value]).range([1, 200]);
for (const item of copyArr) {
if (item.parentId === "0") {
if (item.parentId === "1") {
const val = Number(scale(item.dumpCount).toFixed(4));
res = item;
res.value = val;
@ -145,4 +178,8 @@ watch(
color: red;
margin-top: 20px;
}
.name {
word-wrap: break-word;
}
</style>

View File

@ -111,10 +111,6 @@ function changeType(opt: any[]) {
}
async function createTask() {
if (!labels.value.length) {
ElMessage.warning("no labels");
return;
}
const date = monitorTime.value === "0" ? new Date() : time.value;
const params = {
serviceId: selectorStore.currentService.id,

View File

@ -50,9 +50,14 @@ limitations under the License. -->
@query="searchEndpoints"
/>
</div>
</div>
<div class="row tips">
<b>{{ t("conditionNotice") }}</b>
<el-button
class="search-btn"
size="small"
type="primary"
@click="searchLogs"
>
{{ t("search") }}
</el-button>
</div>
<div class="flex-h row">
<div class="mr-5 traceId" v-show="!isBrowser">
@ -61,6 +66,9 @@ limitations under the License. -->
</div>
<ConditionTags :type="'LOG'" @update="updateTags" />
</div>
<div class="row tips">
<b>{{ t("conditionNotice") }}</b>
</div>
<div class="flex-h" v-show="!isBrowser">
<div class="mr-5" v-show="logStore.supportQueryLogsByKeywords">
<span class="mr-5 grey">{{ t("keywordsOfContent") }}:</span>
@ -109,14 +117,6 @@ limitations under the License. -->
</span>
</el-tooltip>
</div>
<el-button
class="search-btn"
size="small"
type="primary"
@click="searchLogs"
>
{{ t("search") }}
</el-button>
</div>
</template>
<script lang="ts" setup>
@ -326,6 +326,7 @@ watch(
.row {
margin-bottom: 5px;
position: relative;
}
.inputs-max {
@ -337,8 +338,11 @@ watch(
}
.search-btn {
margin-left: 20px;
position: absolute;
top: 0;
right: 10px;
cursor: pointer;
width: 120px;
}
.tips {

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. -->
<template>
<div class="flex-h row">
<div class="mr-5" v-if="dashboardStore.entity === EntityType[1].value">
<div class="mr-10" v-if="dashboardStore.entity === EntityType[1].value">
<span class="grey mr-5">{{ t("service") }}:</span>
<Selector
size="small"
@ -24,7 +24,7 @@ limitations under the License. -->
@change="changeField('service', $event)"
/>
</div>
<div class="mr-5" v-if="dashboardStore.entity !== EntityType[3].value">
<div class="mr-10" v-if="dashboardStore.entity !== EntityType[3].value">
<span class="grey mr-5">{{ t("instance") }}:</span>
<Selector
size="small"
@ -34,7 +34,7 @@ limitations under the License. -->
@change="changeField('instance', $event)"
/>
</div>
<div class="mr-5" v-if="dashboardStore.entity !== EntityType[2].value">
<div class="mr-10" v-if="dashboardStore.entity !== EntityType[2].value">
<span class="grey mr-5">{{ t("endpoint") }}:</span>
<Selector
size="small"
@ -46,7 +46,7 @@ limitations under the License. -->
@query="searchEndpoints"
/>
</div>
<div class="mr-5">
<div class="mr-10">
<span class="grey mr-5">{{ t("status") }}:</span>
<Selector
size="small"
@ -56,27 +56,29 @@ limitations under the License. -->
@change="changeField('status', $event)"
/>
</div>
<div class="mr-5">
<el-button
size="small"
type="primary"
@click="searchTraces"
class="search-btn"
>
{{ t("search") }}
</el-button>
</div>
<div class="flex-h row">
<div class="mr-10">
<span class="grey mr-5">{{ t("traceID") }}:</span>
<el-input size="small" v-model="traceId" class="traceId" />
</div>
</div>
<div class="flex-h">
<div class="mr-5">
<div class="mr-10">
<span class="sm b grey mr-5">{{ t("duration") }}:</span>
<el-input size="small" class="inputs mr-5" v-model="minTraceDuration" />
<span class="grey mr-5">-</span>
<el-input size="small" class="inputs" v-model="maxTraceDuration" />
</div>
</div>
<div class="flex-h">
<ConditionTags :type="'TRACE'" @update="updateTags" />
<el-button
class="search-btn"
size="small"
type="primary"
@click="searchTraces"
>
{{ t("search") }}
</el-button>
</div>
</template>
<script lang="ts" setup>
@ -109,10 +111,6 @@ const state = reactive<any>({
service: { value: "", label: "" },
});
// const dateTime = computed(() => [
// appStore.durationRow.start,
// appStore.durationRow.end,
// ]);
init();
async function init() {
if (dashboardStore.entity === EntityType[1].value) {
@ -241,6 +239,7 @@ watch(
.row {
margin-bottom: 5px;
position: relative;
}
.traceId {
@ -248,7 +247,10 @@ watch(
}
.search-btn {
margin-left: 20px;
cursor: pointer;
width: 120px;
position: absolute;
top: 0;
right: 10px;
}
</style>

View File

@ -200,9 +200,9 @@ export default defineComponent({
dom.style.background = "rgba(0, 0, 0, 0.1)";
}
function selectSpan(event: any) {
const dom = event.path.find((d: any) =>
d.className.includes("trace-item")
);
const dom = event
.composedPath()
.find((d: any) => d.className.includes("trace-item"));
emit("select", props.data);
if (props.headerType === "profile") {
@ -212,9 +212,9 @@ export default defineComponent({
viewSpanDetail(dom);
}
function viewSpan(event: any) {
const dom = event.path.find((d: any) =>
d.className.includes("trace-item")
);
const dom = event
.composedPath()
.find((d: any) => d.className.includes("trace-item"));
emit("select", props.data);
viewSpanDetail(dom);
}