From 8a07b1d804973d7f1ad0916302652892ee9bfcdf Mon Sep 17 00:00:00 2001 From: Fine0830 Date: Sun, 24 Apr 2022 20:24:23 +0800 Subject: [PATCH] feat: Implement the eBPF profile widget on dashboard (#72) --- package-lock.json | 314 ++++++++++++++++-- package.json | 2 + src/assets/icons/insert_chart.svg | 17 + src/assets/icons/view.svg | 15 + src/components/Radio.vue | 4 +- src/components/Selector.vue | 2 +- src/components/index.ts | 2 +- src/graphql/fragments/ebpf.ts | 93 ++++++ src/graphql/index.ts | 2 + src/graphql/query/ebpf.ts | 34 ++ src/locales/lang/en.ts | 5 + src/locales/lang/zh.ts | 5 + src/main.ts | 2 +- src/store/modules/dashboard.ts | 7 +- src/store/modules/ebpf.ts | 153 +++++++++ src/store/modules/profile.ts | 30 +- src/store/modules/trace.ts | 10 +- src/styles/{index.scss => index.ts} | 9 +- src/types/{dashboard.ts => dashboard.d.ts} | 0 src/types/ebpf.d.ts | 76 +++++ src/views/dashboard/List.vue | 2 +- src/views/dashboard/controls/Ebpf.vue | 95 ++++++ src/views/dashboard/controls/Tab.vue | 7 +- src/views/dashboard/controls/index.ts | 3 +- src/views/dashboard/data.ts | 5 +- src/views/dashboard/panel/Layout.vue | 4 +- src/views/dashboard/panel/Tool.vue | 56 +++- src/views/dashboard/related/ebpf/Content.vue | 50 +++ src/views/dashboard/related/ebpf/Header.vue | 104 ++++++ .../related/ebpf/components/EBPFSchedules.vue | 244 ++++++++++++++ .../related/ebpf/components/EBPFStack.vue | 148 +++++++++ .../related/ebpf/components/NewTask.vue | 165 +++++++++ .../related/ebpf/components/TaskList.vue | 195 +++++++++++ .../dashboard/related/ebpf/components/data.ts | 51 +++ .../dashboard/related/profile/Header.vue | 52 +-- .../related/profile/components/NewTask.vue | 34 +- .../related/profile/components/TaskList.vue | 2 +- src/views/dashboard/related/trace/Detail.vue | 8 +- 38 files changed, 1894 insertions(+), 113 deletions(-) create mode 100644 src/assets/icons/insert_chart.svg create mode 100644 src/assets/icons/view.svg create mode 100644 src/graphql/fragments/ebpf.ts create mode 100644 src/graphql/query/ebpf.ts create mode 100644 src/store/modules/ebpf.ts rename src/styles/{index.scss => index.ts} (77%) rename src/types/{dashboard.ts => dashboard.d.ts} (100%) create mode 100644 src/types/ebpf.d.ts create mode 100644 src/views/dashboard/controls/Ebpf.vue create mode 100644 src/views/dashboard/related/ebpf/Content.vue create mode 100644 src/views/dashboard/related/ebpf/Header.vue create mode 100644 src/views/dashboard/related/ebpf/components/EBPFSchedules.vue create mode 100644 src/views/dashboard/related/ebpf/components/EBPFStack.vue create mode 100644 src/views/dashboard/related/ebpf/components/NewTask.vue create mode 100644 src/views/dashboard/related/ebpf/components/TaskList.vue create mode 100644 src/views/dashboard/related/ebpf/components/data.ts diff --git a/package-lock.json b/package-lock.json index 416405a6..9993f986 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,11 +10,13 @@ "dependencies": { "axios": "^0.24.0", "d3": "^7.3.0", + "d3-flame-graph": "^4.1.3", "d3-tip": "^0.9.1", "echarts": "^5.2.2", "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", @@ -1810,6 +1812,18 @@ "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", @@ -3299,6 +3313,12 @@ "@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", @@ -7881,8 +7901,7 @@ "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==", - "dev": true + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "node_modules/compressible": { "version": "2.0.18", @@ -8694,6 +8713,12 @@ "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", @@ -9104,6 +9129,16 @@ "node": ">=0.8" } }, + "node_modules/cypress/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, "node_modules/d3": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/d3/-/d3-7.3.0.tgz", @@ -9306,6 +9341,21 @@ "node": ">=12" } }, + "node_modules/d3-flame-graph": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/d3-flame-graph/-/d3-flame-graph-4.1.3.tgz", + "integrity": "sha512-NijuhJZhaTMwobVgwGQ67x9PovqMMHXBbs0FMHEGJvsWZGuL4M7OsB03v8mHdyVyHhnQYGsYnb5w021e9+R+RQ==", + "dependencies": { + "d3-array": "^3.1.1", + "d3-dispatch": "^3.0.1", + "d3-ease": "^3.0.1", + "d3-format": "^3.0.1", + "d3-hierarchy": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, "node_modules/d3-force": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", @@ -16412,6 +16462,12 @@ "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", @@ -18203,7 +18259,6 @@ "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": "*" } @@ -21672,6 +21727,15 @@ "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", @@ -22411,6 +22475,16 @@ "request": "^2.34" } }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -23746,15 +23820,6 @@ "ms": "^2.1.1" } }, - "node_modules/sockjs/node_modules/uuid": { - "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" - } - }, "node_modules/sort-keys": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", @@ -26807,13 +26872,11 @@ } }, "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "bin": { - "uuid": "bin/uuid" + "uuid": "dist/bin/uuid" } }, "node_modules/v8-compile-cache": { @@ -26871,6 +26934,59 @@ "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", @@ -28266,6 +28382,16 @@ "node": ">= 6" } }, + "node_modules/webpack-log/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, "node_modules/webpack-merge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", @@ -28709,6 +28835,28 @@ "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", @@ -30163,6 +30311,15 @@ } } }, + "@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", @@ -31426,6 +31583,12 @@ "@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", @@ -35117,8 +35280,7 @@ "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==", - "dev": true + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "compressible": { "version": "2.0.18", @@ -35759,6 +35921,12 @@ "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", @@ -36098,6 +36266,12 @@ "psl": "^1.1.24", "punycode": "^1.4.1" } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true } } }, @@ -36249,6 +36423,21 @@ "d3-dsv": "1 - 3" } }, + "d3-flame-graph": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/d3-flame-graph/-/d3-flame-graph-4.1.3.tgz", + "integrity": "sha512-NijuhJZhaTMwobVgwGQ67x9PovqMMHXBbs0FMHEGJvsWZGuL4M7OsB03v8mHdyVyHhnQYGsYnb5w021e9+R+RQ==", + "requires": { + "d3-array": "^3.1.1", + "d3-dispatch": "^3.0.1", + "d3-ease": "^3.0.1", + "d3-format": "^3.0.1", + "d3-hierarchy": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, "d3-force": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", @@ -41825,6 +42014,12 @@ "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", @@ -43211,8 +43406,7 @@ "moment": { "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 + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" }, "move-concurrently": { "version": "1.0.1", @@ -45877,6 +46071,13 @@ "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", @@ -46435,6 +46636,14 @@ "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } } }, "request-progress": { @@ -47531,14 +47740,6 @@ "faye-websocket": "^0.11.3", "uuid": "^8.3.2", "websocket-driver": "^0.7.4" - }, - "dependencies": { - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true - } } }, "sockjs-client": { @@ -49976,10 +50177,9 @@ "dev": true }, "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, "v8-compile-cache": { "version": "2.3.0", @@ -50028,6 +50228,26 @@ } } }, + "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", @@ -51307,6 +51527,14 @@ "requires": { "ansi-colors": "^3.0.0", "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } } }, "webpack-merge": { @@ -51531,6 +51759,24 @@ "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", diff --git a/package.json b/package.json index ba4a893c..66a6188d 100644 --- a/package.json +++ b/package.json @@ -12,11 +12,13 @@ "dependencies": { "axios": "^0.24.0", "d3": "^7.3.0", + "d3-flame-graph": "^4.1.3", "d3-tip": "^0.9.1", "echarts": "^5.2.2", "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", diff --git a/src/assets/icons/insert_chart.svg b/src/assets/icons/insert_chart.svg new file mode 100644 index 00000000..4ab30638 --- /dev/null +++ b/src/assets/icons/insert_chart.svg @@ -0,0 +1,17 @@ + + + + diff --git a/src/assets/icons/view.svg b/src/assets/icons/view.svg new file mode 100644 index 00000000..4122084d --- /dev/null +++ b/src/assets/icons/view.svg @@ -0,0 +1,15 @@ + + diff --git a/src/components/Radio.vue b/src/components/Radio.vue index f5aee030..7eafaa4e 100644 --- a/src/components/Radio.vue +++ b/src/components/Radio.vue @@ -32,7 +32,7 @@ interface Option { const emit = defineEmits(["change"]); const props = defineProps({ options: { - type: Array as PropType<(Option & { disabled: boolean })[]>, + type: Array as PropType, default: () => [], }, value: { @@ -44,7 +44,7 @@ const props = defineProps({ const selected = ref(props.value); -function checked(opt: string) { +function checked(opt: unknown) { emit("change", opt); } diff --git a/src/components/Selector.vue b/src/components/Selector.vue index 2501195f..515a2226 100644 --- a/src/components/Selector.vue +++ b/src/components/Selector.vue @@ -58,7 +58,7 @@ const props = defineProps({ }, size: { type: null, default: "default" }, placeholder: { - type: [String, Number] as PropType, + type: [String, undefined] as PropType, default: "Select a option", }, borderRadius: { type: Number, default: 3 }, diff --git a/src/components/index.ts b/src/components/index.ts index 6417e237..8d8a5a96 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -14,13 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import type { App } from "vue"; import Icon from "./Icon.vue"; import TimePicker from "./TimePicker.vue"; import Selector from "./Selector.vue"; import Graph from "./Graph.vue"; import Radio from "./Radio.vue"; import SelectSingle from "./SelectSingle.vue"; -import type { App } from "vue"; import VueGridLayout from "vue-grid-layout"; const components: { [key: string]: any } = { diff --git a/src/graphql/fragments/ebpf.ts b/src/graphql/fragments/ebpf.ts new file mode 100644 index 00000000..662cfb31 --- /dev/null +++ b/src/graphql/fragments/ebpf.ts @@ -0,0 +1,93 @@ +/** + * 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. + */ + +export const queryCreateTaskData = { + variable: "$serviceId: ID!", + query: ` + createTaskData: queryPrepareCreateEBPFProfilingTaskData(serviceId: $serviceId) { + couldProfiling + processLabels + }`, +}; +export const createEBPFTask = { + variable: "$request: EBPFProfilingTaskFixedTimeCreationRequest!", + query: ` + createTaskData: createEBPFProfilingFixedTimeTask(request: $request) { + status + errorReason + id + }`, +}; +export const queryEBPFTasks = { + variable: "$serviceId: ID!", + query: ` + queryEBPFTasks: queryEBPFProfilingTasks(serviceId: $serviceId) { + taskId + serviceName + serviceId + processLabels + taskStartTime + triggerType + fixedTriggerDuration + targetType + createTime + }`, +}; +export const queryEBPFSchedules = { + variable: "$taskId: ID!, $duration: Duration!", + query: ` + eBPFSchedules: queryEBPFProfilingSchedules(taskId: $taskId, duration: $duration) { + scheduleId + taskId + process { + id + name + serviceId + serviceName + instanceId + instanceName + layer + agentId + detectType + attributes { + name + value + } + labels + } + startTime + endTime + }`, +}; + +export const analysisEBPFResult = { + variable: + "$scheduleIdList: [ID!]!, $timeRanges: [EBPFProfilingAnalyzeTimeRange!]!", + query: ` + analysisEBPFResult: analysisEBPFProfilingResult(scheduleIdList: $scheduleIdList, timeRanges: $timeRanges) { + tip + trees { + elements { + id + parentId + symbol + stackType + dumpCount + } + } + }`, +}; diff --git a/src/graphql/index.ts b/src/graphql/index.ts index ab6fd319..3b76c9fb 100644 --- a/src/graphql/index.ts +++ b/src/graphql/index.ts @@ -25,6 +25,7 @@ import * as log from "./query/log"; import * as profile from "./query/profile"; import * as alarm from "./query/alarm"; import * as event from "./query/event"; +import * as ebpf from "./query/ebpf"; const query: { [key: string]: string } = { ...app, @@ -36,6 +37,7 @@ const query: { [key: string]: string } = { ...profile, ...alarm, ...event, + ...ebpf, }; class Graphql { private queryData = ""; diff --git a/src/graphql/query/ebpf.ts b/src/graphql/query/ebpf.ts new file mode 100644 index 00000000..131b57a3 --- /dev/null +++ b/src/graphql/query/ebpf.ts @@ -0,0 +1,34 @@ +/** + * 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. + */ + +import { + queryCreateTaskData, + createEBPFTask, + queryEBPFTasks, + queryEBPFSchedules, + analysisEBPFResult, +} from "../fragments/ebpf"; + +export const getCreateTaskData = `query queryCreateTaskData(${queryCreateTaskData.variable}) {${queryCreateTaskData.query}}`; + +export const saveEBPFTask = `mutation createEBPFTask(${createEBPFTask.variable}) {${createEBPFTask.query}}`; + +export const getEBPFTasks = `query queryEBPFTasks(${queryEBPFTasks.variable}) {${queryEBPFTasks.query}}`; + +export const getEBPFSchedules = `query queryEBPFSchedules(${queryEBPFSchedules.variable}) {${queryEBPFSchedules.query}}`; + +export const getEBPFResult = `query analysisEBPFResult(${analysisEBPFResult.variable}) {${analysisEBPFResult.query}}`; diff --git a/src/locales/lang/en.ts b/src/locales/lang/en.ts index d4b0be3b..7a5a3503 100644 --- a/src/locales/lang/en.ts +++ b/src/locales/lang/en.ts @@ -131,6 +131,11 @@ const msg = { metricLabel: "Metric Label", showUnit: "Show Unit", noGraph: "No Graph", + taskId: "Task ID", + triggerType: "Trigger Type", + targetType: "Target Type", + ebpfTip: "Don't have process could profiling", + processSelect: "Click to select processes", hourTip: "Select Hour", minuteTip: "Select Minute", secondTip: "Select Second", diff --git a/src/locales/lang/zh.ts b/src/locales/lang/zh.ts index 476dd473..d14876be 100644 --- a/src/locales/lang/zh.ts +++ b/src/locales/lang/zh.ts @@ -129,6 +129,11 @@ const msg = { metricLabel: "指标标签", showUnit: "显示单位", noGraph: "无图表", + taskId: "任务ID", + triggerType: "触发类型", + targetType: "目标类型", + processSelect: "点击选择进程", + ebpfTip: "没有进程可以分析", hourTip: "选择小时", minuteTip: "选择分钟", secondTip: "选择秒数", diff --git a/src/main.ts b/src/main.ts index f9694ae6..9e737946 100644 --- a/src/main.ts +++ b/src/main.ts @@ -20,7 +20,7 @@ import router from "./router"; import { store } from "./store"; import components from "@/components"; import i18n from "./locales"; -import "./styles/index.scss"; +import "./styles/index.ts"; const app = createApp(App); diff --git a/src/store/modules/dashboard.ts b/src/store/modules/dashboard.ts index 93df9a64..17bf3fde 100644 --- a/src/store/modules/dashboard.ts +++ b/src/store/modules/dashboard.ts @@ -114,7 +114,12 @@ export const dashboardStore = defineStore({ : 3, }; } - if (type === "Trace" || type === "Profile" || type === "Log") { + if ( + type === "Trace" || + type === "Profile" || + type === "Log" || + type === "Ebpf" + ) { newItem.h = 36; } if (type === "Text") { diff --git a/src/store/modules/ebpf.ts b/src/store/modules/ebpf.ts new file mode 100644 index 00000000..b03bed73 --- /dev/null +++ b/src/store/modules/ebpf.ts @@ -0,0 +1,153 @@ +/** + * 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. + */ +import { defineStore } from "pinia"; +import { Duration, Option } from "@/types/app"; +import { + EBPFTaskCreationRequest, + EBPFProfilingSchedule, + EBPFTaskList, + AnalyzationTrees, +} from "@/types/ebpf"; +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; + analyzeTrees: AnalyzationTrees[]; + labels: Option[]; + couldProfiling: boolean; + tip: string; +} + +export const ebpfStore = defineStore({ + id: "eBPF", + state: (): EbpfStore => ({ + durationTime: useAppStoreWithOut().durationTime, + taskList: [], + eBPFSchedules: [], + currentSchedule: {}, + analyzeTrees: [], + labels: [{ value: "", label: "" }], + couldProfiling: false, + tip: "", + }), + actions: { + setCurrentSpan(span: Span) { + this.currentSpan = span; + }, + setCurrentSchedule(s: Trace) { + this.currentSchedule = s; + }, + async getCreateTaskData(serviceId: string) { + const res: AxiosResponse = await graphql + .query("getCreateTaskData") + .params({ serviceId }); + + if (res.data.errors) { + return res.data; + } + const json = res.data.data.createTaskData; + this.couldProfiling = json.couldProfiling || false; + this.labels = json.processLabels.map((d: string) => { + return { label: d, value: d }; + }); + return res.data; + }, + async createTask(param: EBPFTaskCreationRequest) { + const res: AxiosResponse = await graphql + .query("saveEBPFTask") + .params({ request: param }); + + if (res.data.errors) { + return res.data; + } + this.getTaskList(param.serviceId); + return res.data; + }, + async getTaskList(serviceId: string) { + const res: AxiosResponse = await graphql + .query("getEBPFTasks") + .params({ serviceId }); + + this.tip = ""; + if (res.data.errors) { + return res.data; + } + this.taskList = res.data.data.queryEBPFTasks.reverse() || []; + if (!this.taskList.length) { + return res.data; + } + this.getEBPFSchedules({ taskId: this.taskList[0].taskId }); + return res.data; + }, + async getEBPFSchedules(params: { taskId: string; duration?: Duration }) { + const duration = useAppStoreWithOut().durationTime; + const res: AxiosResponse = await graphql + .query("getEBPFSchedules") + .params({ ...params, duration }); + + if (res.data.errors) { + this.eBPFSchedules = []; + return res.data; + } + this.tip = ""; + const { eBPFSchedules } = res.data.data; + + this.eBPFSchedules = eBPFSchedules; + if (!eBPFSchedules.length) { + this.eBPFSchedules = []; + } + this.analyzeTrees = []; + return res.data; + }, + async getEBPFAnalyze(params: { + scheduleIdList: string[]; + timeRanges: Array<{ start: number; end: number }>; + }) { + const res: AxiosResponse = await graphql + .query("getEBPFResult") + .params(params); + + if (res.data.errors) { + this.analyzeTrees = []; + return res.data; + } + const { analysisEBPFResult } = res.data.data; + this.tip = analysisEBPFResult.tip; + if (!analysisEBPFResult) { + this.analyzeTrees = []; + return res.data; + } + if (analysisEBPFResult.tip) { + this.analyzeTrees = []; + return res.data; + } + this.analyzeTrees = analysisEBPFResult.trees[0].elements; + return res.data; + }, + }, +}); + +export function useEbpfStore(): any { + return ebpfStore(store); +} diff --git a/src/store/modules/profile.ts b/src/store/modules/profile.ts index 10f9e308..9209e395 100644 --- a/src/store/modules/profile.ts +++ b/src/store/modules/profile.ts @@ -16,7 +16,7 @@ */ import { defineStore } from "pinia"; import { Duration } from "@/types/app"; -import { Service } from "@/types/selector"; +import { Endpoint } from "@/types/selector"; import { TaskListItem, SegmentSpan, @@ -31,7 +31,8 @@ import { AxiosResponse } from "axios"; import { useAppStoreWithOut } from "@/store/modules/app"; interface ProfileState { - services: Service[]; + endpoints: Endpoint[]; + taskEndpoints: Endpoint[]; durationTime: Duration; condition: { serviceId: string; endpointName: string }; taskList: TaskListItem[]; @@ -47,7 +48,8 @@ interface ProfileState { export const profileStore = defineStore({ id: "profile", state: (): ProfileState => ({ - services: [{ value: "0", label: "All" }], + endpoints: [{ value: "", label: "All" }], + taskEndpoints: [{ value: "", label: "All" }], durationTime: useAppStoreWithOut().durationTime, condition: { serviceId: "", endpointName: "" }, taskList: [], @@ -75,14 +77,28 @@ export const profileStore = defineStore({ setHighlightTop() { this.highlightTop = !this.highlightTop; }, - async getServices(layer: string) { - const res: AxiosResponse = await graphql.query("queryServices").params({ - layer, + async getEndpoints(serviceId: string, keyword?: string) { + const res: AxiosResponse = await graphql.query("queryEndpoints").params({ + serviceId, + duration: this.durationTime, + keyword: keyword || "", }); if (res.data.errors) { return res.data; } - this.services = res.data.data.services; + this.endpoints = [{ value: "", label: "All" }, ...res.data.data.pods]; + return res.data; + }, + async getTaskEndpoints(serviceId: string, keyword?: string) { + const res: AxiosResponse = await graphql.query("queryEndpoints").params({ + serviceId, + duration: this.durationTime, + keyword: keyword || "", + }); + if (res.data.errors) { + return res.data; + } + this.taskEndpoints = [{ value: "", label: "All" }, ...res.data.data.pods]; return res.data; }, async getTaskList() { diff --git a/src/store/modules/trace.ts b/src/store/modules/trace.ts index a7178a0d..794cdffa 100644 --- a/src/store/modules/trace.ts +++ b/src/store/modules/trace.ts @@ -95,10 +95,7 @@ export const traceStore = defineStore({ if (res.data.errors) { return res.data; } - this.instances = [ - { value: "0", label: "All" }, - ...res.data.data.pods, - ] || [{ value: " 0", label: "All" }]; + this.instances = [{ value: "0", label: "All" }, ...res.data.data.pods]; return res.data; }, async getEndpoints(id: string, keyword?: string) { @@ -113,10 +110,7 @@ export const traceStore = defineStore({ if (res.data.errors) { return res.data; } - this.endpoints = [ - { value: "0", label: "All" }, - ...res.data.data.pods, - ] || [{ value: "0", label: "All" }]; + this.endpoints = [{ value: "0", label: "All" }, ...res.data.data.pods]; return res.data; }, async getTraces() { diff --git a/src/styles/index.scss b/src/styles/index.ts similarity index 77% rename from src/styles/index.scss rename to src/styles/index.ts index ce0421bb..4f098aa6 100644 --- a/src/styles/index.scss +++ b/src/styles/index.ts @@ -14,6 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@import "./grid.scss"; -@import "./lib.scss"; -@import "./reset.scss"; +import "element-plus/es/components/message/style/css"; +import "element-plus/es/components/message-box/style/css"; +import "element-plus/es/components/notification/style/css"; +import "./grid.scss"; +import "./lib.scss"; +import "./reset.scss"; diff --git a/src/types/dashboard.ts b/src/types/dashboard.d.ts similarity index 100% rename from src/types/dashboard.ts rename to src/types/dashboard.d.ts diff --git a/src/types/ebpf.d.ts b/src/types/ebpf.d.ts new file mode 100644 index 00000000..7ca3febc --- /dev/null +++ b/src/types/ebpf.d.ts @@ -0,0 +1,76 @@ +/** + * 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. + */ + +export interface EBPFTaskCreationRequest { + serviceId: string; + processLabels: string[]; + startTime: number; + duration: number; + targetType: string; +} + +export interface EBPFTaskList { + taskId: string; + serviceName: string; + serviceId: string; + processLabels: string[]; + taskStartTime: number; + fixedTriggerDuration: number; + targetType: string; + createTime: number; + triggerType: string; +} + +export interface EBPFProfilingSchedule { + scheduleId: string; + taskId: string; + process: Process; + endTime: number; + startTime: number; +} + +export type Process = { + id: string; + name: string; + serviceId: string; + serviceName: string; + instanceId: string; + instanceName: string; + layer: string; + agentId: string; + detectType: string; + attributes: { name: string; value: string }; + labels: string[]; +}; +export type StackElement = { + id: string; + originId: string; + name: string; + parentId: string; + symbol: string; + dumpCount: number; + stackType: string; + value: number; + children?: StackElement[]; +}; +export type AnalyzationTrees = { + id: string; + parentId: string; + symbol: string; + dumpCount: number; + stackType: string; +}; diff --git a/src/views/dashboard/List.vue b/src/views/dashboard/List.vue index 99f62b50..5224bd37 100644 --- a/src/views/dashboard/List.vue +++ b/src/views/dashboard/List.vue @@ -44,7 +44,7 @@ limitations under the License. --> :style="{ fontSize: '13px', width: '100%' }" v-loading="loading" ref="multipleTableRef" - :default-sort="{ prop: 'name' }" + :default-sort="{ prop: 'name', order: 'ascending' }" @selection-change="handleSelectionChange" height="637px" size="small" diff --git a/src/views/dashboard/controls/Ebpf.vue b/src/views/dashboard/controls/Ebpf.vue new file mode 100644 index 00000000..78f67ef7 --- /dev/null +++ b/src/views/dashboard/controls/Ebpf.vue @@ -0,0 +1,95 @@ + + + + diff --git a/src/views/dashboard/controls/Tab.vue b/src/views/dashboard/controls/Tab.vue index 7d153960..3ce22394 100644 --- a/src/views/dashboard/controls/Tab.vue +++ b/src/views/dashboard/controls/Tab.vue @@ -97,7 +97,7 @@ limitations under the License. --> :key="item.i" @click="clickTabGrid($event, item)" :class="{ active: activeTabWidget === item.i }" - drag-ignore-from="svg.d3-trace-tree, .dragger, .micro-topo-chart" + :drag-ignore-from="dragIgnoreFrom" > :key="item.i" @click="clickGrid(item)" :class="{ active: dashboardStore.activedGridItem === item.i }" - drag-ignore-from="svg.d3-trace-tree, .dragger, .micro-topo-chart" + :drag-ignore-from="dragIgnoreFrom" > @@ -45,6 +45,7 @@ import { useDashboardStore } from "@/store/modules/dashboard"; import { useSelectorStore } from "@/store/modules/selectors"; import { LayoutConfig } from "@/types/dashboard"; import controls from "../controls/index"; +import { dragIgnoreFrom } from "../data"; export default defineComponent({ name: "Layout", @@ -72,6 +73,7 @@ export default defineComponent({ dashboardStore, clickGrid, t, + dragIgnoreFrom, }; }, }); diff --git a/src/views/dashboard/panel/Tool.vue b/src/views/dashboard/panel/Tool.vue index 2c079d76..6d0339b0 100644 --- a/src/views/dashboard/panel/Tool.vue +++ b/src/views/dashboard/panel/Tool.vue @@ -258,7 +258,7 @@ async function setSourceSelector() { let currentPod; if (states.currentPod) { currentPod = selectorStore.pods.find( - (d: { id: string }) => d.label === states.currentPod + (d: { label: string }) => d.label === states.currentPod ); } else { currentPod = selectorStore.pods.find((d: { id: string }) => d.id === pod); @@ -283,10 +283,10 @@ async function setDestSelector() { return; } const destPod = params.destPodId || selectorStore.destPods[0].id; - let currentDestPod = ""; + let currentDestPod = { label: "" }; if (states.currentDestPod) { currentDestPod = selectorStore.pods.find( - (d: { id: string }) => d.label === states.currentDestPod + (d: { label: string }) => d.label === states.currentDestPod ); } else { currentDestPod = selectorStore.destPods.find( @@ -317,19 +317,23 @@ async function getServices() { let s; if (states.currentService) { s = (selectorStore.services || []).find( - (d) => d.label === states.currentService + (d: { label: string }) => d.label === states.currentService ); } else { - s = (selectorStore.services || []).find((d, index) => index === 0); + s = (selectorStore.services || []).find( + (d: unknown, index: number) => index === 0 + ); } selectorStore.setCurrentService(s || null); let d; if (states.currentService) { d = (selectorStore.services || []).find( - (d) => d.label === states.currentDestService + (d: { label: string }) => d.label === states.currentDestService ); } else { - d = (selectorStore.services || []).find((d, index) => index === 1); + d = (selectorStore.services || []).find( + (d: unknown, index: number) => index === 1 + ); } selectorStore.setCurrentDestService(d || null); if (!selectorStore.currentService) { @@ -431,6 +435,9 @@ function setTabControls(id: string) { case "addProfile": dashboardStore.addTabControls("Profile"); break; + case "addEbpf": + dashboardStore.addTabControls("Ebpf"); + break; case "addTopology": dashboardStore.addTabControls("Topology"); break; @@ -457,6 +464,9 @@ function setControls(id: string) { case "addProfile": dashboardStore.addControl("Profile"); break; + case "addEbpf": + dashboardStore.addControl("Ebpf"); + break; case "addLog": dashboardStore.addControl("Log"); break; @@ -484,9 +494,13 @@ async function fetchPods( if (setPod) { let p; if (states.currentPod) { - p = selectorStore.pods.find((d) => d.label === states.currentPod); + p = selectorStore.pods.find( + (d: { label: unknown }) => d.label === states.currentPod + ); } else { - p = selectorStore.pods.find((d, index) => index === 0); + p = selectorStore.pods.find( + (d: unknown, index: number) => index === 0 + ); } selectorStore.setCurrentPod(p || null); states.currentPod = selectorStore.currentPod.label; @@ -497,9 +511,13 @@ async function fetchPods( if (setPod) { let p; if (states.currentPod) { - p = selectorStore.pods.find((d) => d.label === states.currentPod); + p = selectorStore.pods.find( + (d: { label: string }) => d.label === states.currentPod + ); } else { - p = selectorStore.pods.find((d, index) => index === 0); + p = selectorStore.pods.find( + (d: { label: string }, index: number) => index === 0 + ); } selectorStore.setCurrentPod(p || null); states.currentPod = selectorStore.currentPod.label; @@ -514,9 +532,13 @@ async function fetchPods( if (setPod) { let p; if (states.currentDestPod) { - p = selectorStore.pods.find((d) => d.label === states.currentDestPod); + p = selectorStore.pods.find( + (d: { label: string }) => d.label === states.currentDestPod + ); } else { - p = selectorStore.pods.find((d, index) => index === 0); + p = selectorStore.pods.find( + (d: { label: string }, index: number) => index === 0 + ); } selectorStore.setCurrentDestPod(p || null); states.currentDestPod = selectorStore.currentDestPod.label; @@ -530,9 +552,13 @@ async function fetchPods( if (setPod) { let p; if (states.currentDestPod) { - p = selectorStore.pods.find((d) => d.label === states.currentDestPod); + p = selectorStore.pods.find( + (d: { label: string }) => d.label === states.currentDestPod + ); } else { - p = selectorStore.pods.find((d, index) => index === 0); + p = selectorStore.pods.find( + (d: { label: string }, index: number) => index === 0 + ); } selectorStore.setCurrentDestPod(p || null); states.currentDestPod = selectorStore.currentDestPod.label; diff --git a/src/views/dashboard/related/ebpf/Content.vue b/src/views/dashboard/related/ebpf/Content.vue new file mode 100644 index 00000000..e4b0653b --- /dev/null +++ b/src/views/dashboard/related/ebpf/Content.vue @@ -0,0 +1,50 @@ + + + + diff --git a/src/views/dashboard/related/ebpf/Header.vue b/src/views/dashboard/related/ebpf/Header.vue new file mode 100644 index 00000000..da7a809f --- /dev/null +++ b/src/views/dashboard/related/ebpf/Header.vue @@ -0,0 +1,104 @@ + + + + diff --git a/src/views/dashboard/related/ebpf/components/EBPFSchedules.vue b/src/views/dashboard/related/ebpf/components/EBPFSchedules.vue new file mode 100644 index 00000000..cfdcd91c --- /dev/null +++ b/src/views/dashboard/related/ebpf/components/EBPFSchedules.vue @@ -0,0 +1,244 @@ + + + + diff --git a/src/views/dashboard/related/ebpf/components/EBPFStack.vue b/src/views/dashboard/related/ebpf/components/EBPFStack.vue new file mode 100644 index 00000000..d2776e3a --- /dev/null +++ b/src/views/dashboard/related/ebpf/components/EBPFStack.vue @@ -0,0 +1,148 @@ + + + + diff --git a/src/views/dashboard/related/ebpf/components/NewTask.vue b/src/views/dashboard/related/ebpf/components/NewTask.vue new file mode 100644 index 00000000..5a0e63cc --- /dev/null +++ b/src/views/dashboard/related/ebpf/components/NewTask.vue @@ -0,0 +1,165 @@ + + + + + diff --git a/src/views/dashboard/related/ebpf/components/TaskList.vue b/src/views/dashboard/related/ebpf/components/TaskList.vue new file mode 100644 index 00000000..65c93ce5 --- /dev/null +++ b/src/views/dashboard/related/ebpf/components/TaskList.vue @@ -0,0 +1,195 @@ + + + + diff --git a/src/views/dashboard/related/ebpf/components/data.ts b/src/views/dashboard/related/ebpf/components/data.ts new file mode 100644 index 00000000..a538897c --- /dev/null +++ b/src/views/dashboard/related/ebpf/components/data.ts @@ -0,0 +1,51 @@ +/** + * 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. + */ +export const ProfileMode: any[] = [ + { label: "Include Children", value: "include" }, + { label: "Exclude Children", value: "exclude" }, +]; +export const NewTaskField = { + service: { key: "", label: "None" }, + monitorTime: { key: "0", label: "monitor now" }, + monitorDuration: { key: 5, label: "5 min" }, + minThreshold: 0, + dumpPeriod: { key: 10, label: "10ms" }, + endpointName: "", + maxSamplingCount: { key: 5, label: "5" }, +}; + +export const TargetTypes = [{ label: "ON_CPU", value: "ON_CPU" }]; + +export const InitTaskField = { + monitorTimeEn: [ + { value: "0", label: "monitor now" }, + { value: "1", label: "set start time" }, + ], + monitorTimeCn: [ + { value: "0", label: "此刻" }, + { value: "1", label: "设置时间" }, + ], + monitorDuration: [ + { value: "5", label: "5 min" }, + { value: "10", label: "10 min" }, + { value: "15", label: "15 min" }, + ], +}; +export const TableHeader = [ + { property: "name", label: "Name" }, + { property: "instanceName", label: "Instance Name" }, +]; diff --git a/src/views/dashboard/related/profile/Header.vue b/src/views/dashboard/related/profile/Header.vue index e2215391..09bc13b9 100644 --- a/src/views/dashboard/related/profile/Header.vue +++ b/src/views/dashboard/related/profile/Header.vue @@ -14,19 +14,18 @@ See the License for the specific language governing permissions and limitations under the License. -->