| <!-- |
| ~ Licensed to the Apache Software Foundation (ASF) under one or more |
| ~ contributor license agreements. See the NOTICE file distributed with |
| ~ this work for additional information regarding copyright ownership. |
| ~ The ASF licenses this file to You under the Apache License, Version 2.0 |
| ~ (the "License"); you may not use this file except in compliance with |
| ~ the License. You may obtain a copy of the License at |
| ~ |
| ~ http://www.apache.org/licenses/LICENSE-2.0 |
| ~ |
| ~ Unless required by applicable law or agreed to in writing, software |
| ~ distributed under the License is distributed on an "AS IS" BASIS, |
| ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| ~ See the License for the specific language governing permissions and |
| ~ limitations under the License. |
| --> |
| <template> |
| <v-container grid-list-xl fluid> |
| <v-layout row wrap> |
| <!-- <v-flex lg12> |
| <breadcrumb title="metrics" :items="breads"></breadcrumb> |
| </v-flex> |
| <v-flex xs12 > |
| <search id="serviceSearch" v-model="filter" :submit="submit" :label="$t('searchSingleMetrics')"></search> |
| </v-flex> |
| <v-flex lg4 sm6 xs12> |
| <v-card> |
| <v-card-text> |
| <h4>Provider (Total)</h4> |
| <hr style="height:3px;border:none;border-top:3px double #9D9D9D;" /> |
| <chart ref="chart1" :options="provider.qps" :autoresize="true"/> |
| <hr style="height:1px;border:none;border-top:1px solid #ADADAD;" /> |
| <chart ref="chart1" :options="provider.rt" :autoresize="true" /> |
| <hr style="height:1px;border:none;border-top:1px solid #ADADAD;" /> |
| <chart ref="chart1" :options="provider.success_rate" :autoresize="true" /> |
| <hr style="height:1px;border:none;border-top:1px solid #ADADAD;" /> |
| </v-card-text> |
| </v-card> |
| </v-flex> |
| <v-flex lg4 sm6 xs12> |
| <v-card> |
| <v-card-text> |
| <h4>Consumer (Total)</h4> |
| <hr style="height:3px;border:none;border-top:3px double #9D9D9D;" /> |
| <chart ref="chart1" :options="consumer.qps" :autoresize="true" /> |
| <hr style="height:1px;border:none;border-top:1px solid #ADADAD;" /> |
| <chart ref="chart1" :options="consumer.rt" :autoresize="true" /> |
| <hr style="height:1px;border:none;border-top:1px solid #ADADAD;" /> |
| <chart ref="chart1" :options="consumer.success_rate" :autoresize="true" /> |
| <hr style="height:1px;border:none;border-top:1px solid #ADADAD;" /> |
| </v-card-text> |
| </v-card> |
| </v-flex> |
| <v-flex lg4 sm6 xs12> |
| <v-card> |
| <v-card-text> |
| <h4>Thread Pool</h4> |
| <hr style="height:3px;border:none;border-top:3px double #9D9D9D;" /> |
| <div class="layout row ma-0 align-center justify-space-between"> |
| <div class="text-box"> |
| <div class="subheading pb-2">active count</div> |
| <span class="grey--text">{{this.threadPoolData.active}} <v-icon small color="green">{{this.threadPoolData.active_trending}}</v-icon> </span> |
| </div> |
| <div class="chart"> |
| <v-progress-circular |
| :size="60" |
| :width="5" |
| :rotate="360" |
| :value="this.threadPoolData.activert" |
| color="success" |
| > |
| {{this.threadPoolData.activert}} |
| </v-progress-circular> |
| </div> |
| </div> |
| <hr style="height:1px;border:none;border-top:1px solid #ADADAD;" /> |
| <div class="layout row ma-0 align-center justify-space-between"> |
| <div class="subheading pb-2">core size</div> |
| <span class="grey--text">{{this.threadPoolData.core}} </span> |
| <div class="subheading pb-2">max size</div> |
| <span class="grey--text">{{this.threadPoolData.max}} </span> |
| <div class="subheading pb-2">current size</div> |
| <span class="grey--text">{{this.threadPoolData.current}} </span> |
| <div style="height:60px"></div> |
| <v-icon small color="green">{{this.threadPoolData.current_trending}}</v-icon> |
| </div> |
| <hr style="height:1px;border:none;border-top:1px solid #ADADAD;" /> |
| </v-card-text> |
| </v-card> |
| </v-flex> |
| <v-flex sm12> |
| <h3>{{$t('methodMetrics')}}</h3> |
| </v-flex> |
| <v-flex lg12 > |
| <v-tabs |
| class="elevation-1"> |
| <v-tab> |
| {{$t('providers')}} |
| </v-tab> |
| <v-tab> |
| {{$t('consumers')}} |
| </v-tab> |
| <v-tab-item> |
| <v-data-table |
| id="providerList" |
| class="elevation-1" |
| :headers="headers" |
| :items="providerDetails" |
| > |
| <template slot="items" slot-scope="props"> |
| <td>{{props.item.service}}</td> |
| <td>{{props.item.method}}</td> |
| <td>{{props.item.qps}}</td> |
| <td>{{props.item.rt}}</td> |
| <td>{{props.item.successRate}}</td> |
| </template> |
| </v-data-table> |
| </v-tab-item> |
| <v-tab-item > |
| <v-data-table |
| class="elevation-1" |
| :headers="headers" |
| :items="consumerDetails" |
| > |
| <template slot="items" slot-scope="props"> |
| <td>{{props.item.service}}</td> |
| <td>{{props.item.method}}</td> |
| <td>{{props.item.qps}}</td> |
| <td>{{props.item.rt}}</td> |
| <td>{{props.item.successRate}}</td> |
| </template> |
| </v-data-table> |
| </v-tab-item> |
| </v-tabs> |
| </v-flex> --> |
| <v-flex> |
| <iframe src="http://localhost:8081/dashboard-solo/new?utm_source=grafana_gettingstarted&orgId=1&from=1684139950126&to=1684161550126&panelId=1" width="1350" height="700" frameborder="0"></iframe> |
| </v-flex> |
| </v-layout> |
| </v-container> |
| </template> |
| |
| <script> |
| // import Material from 'vuetify/es5/util/colors' |
| |
| export default { |
| |
| name: 'ServiceMetrics' |
| // components: { |
| // Breadcrumb, |
| // Search |
| // }, |
| // data () { |
| // return { |
| // provider: { |
| // metrics: [ |
| // 'dubbo.provider.qps', 'dubbo.provider.rt', 'dubbo.provider.success_rate' |
| // ], |
| // qps: { |
| // title: { |
| // text: 'qps', |
| // padding: [50, 5, 5, 5], |
| // textStyle: { |
| // fontWeight: 200, |
| // fontSize: 12 |
| // } |
| // }, |
| // tooltip: {}, |
| // xAxis: { |
| // show: false, |
| // type: 'category', |
| // data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
| // }, |
| // yAxis: { |
| // show: false |
| // }, |
| // series: [{ |
| // type: 'line', |
| // data: [] |
| // }] |
| // }, |
| // rt: { |
| // title: { |
| // text: 'rt(ms)', |
| // padding: [50, 5, 5, 5], |
| // textStyle: { |
| // fontWeight: 200, |
| // fontSize: 12 |
| // } |
| // }, |
| // tooltip: {}, |
| // xAxis: { |
| // show: false, |
| // type: 'category', |
| // data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
| // }, |
| // yAxis: { |
| // show: false |
| // }, |
| // series: [{ |
| // type: 'line', |
| // data: [] |
| // }] |
| // }, |
| // success_rate: { |
| // title: { |
| // text: 'success rate', |
| // padding: [50, 5, 5, 5], |
| // textStyle: { |
| // fontWeight: 200, |
| // fontSize: 12 |
| // } |
| // }, |
| // tooltip: {}, |
| // xAxis: { |
| // show: false, |
| // type: 'category', |
| // data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
| // }, |
| // yAxis: { |
| // show: false |
| // }, |
| // series: [{ |
| // type: 'line', |
| // data: [] |
| // }] |
| // } |
| // }, |
| // consumer: { |
| // metrics: [ |
| // 'dubbo.consumer.qps', 'dubbo.consumer.rt', 'dubbo.consumer.success_rate' |
| // ], |
| // qps: { |
| // title: { |
| // text: 'qps', |
| // padding: [50, 5, 5, 5], |
| // textStyle: { |
| // fontWeight: 200, |
| // fontSize: 12 |
| // } |
| |
| // }, |
| // tooltip: {}, |
| // xAxis: { |
| // show: false, |
| // type: 'category', |
| // data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
| // }, |
| // yAxis: { |
| // show: false |
| // }, |
| // series: [{ |
| // type: 'line', |
| // data: [] |
| // }] |
| // }, |
| // rt: { |
| // title: { |
| // text: 'rt(ms)', |
| // padding: [50, 5, 5, 5], |
| // textStyle: { |
| // fontWeight: 200, |
| // fontSize: 12 |
| // } |
| // }, |
| // tooltip: {}, |
| // xAxis: { |
| // show: false, |
| // type: 'category', |
| // data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
| // }, |
| // yAxis: { |
| // show: false |
| // }, |
| // series: [{ |
| // type: 'line', |
| // data: [] |
| // }] |
| // }, |
| // success_rate: { |
| // title: { |
| // text: 'success rate', |
| // padding: [50, 5, 5, 5], |
| // textStyle: { |
| // fontWeight: 200, |
| // fontSize: 12 |
| // } |
| // }, |
| // tooltip: {}, |
| // xAxis: { |
| // show: false, |
| // type: 'category', |
| // data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
| // }, |
| // yAxis: { |
| // show: false |
| // }, |
| // series: [{ |
| // type: 'line', |
| // data: [] |
| // }] |
| // } |
| // }, |
| // threadPoolData: { |
| // core: 0, |
| // max: 0, |
| // current: 0, |
| // current_trending: '', |
| // active: 0, |
| // active_trending: '', |
| // activert: 0 |
| // }, |
| // selectedTab: 'tab-1', |
| // filter: '', |
| // headers: [], |
| // providerDetails: [], |
| // consumerDetails: [], |
| // option: null, |
| // color: Material, |
| // breads: [ |
| // { |
| // text: 'metrics', |
| // href: '' |
| // } |
| // ] |
| |
| // } |
| // }, |
| // /* |
| // * */ |
| // methods: { |
| // submit: function () { |
| // this.searchByIp(this.filter, true) |
| // }, |
| // searchByIp: function (filter, rewrite) { |
| // if (this.filter === '') { |
| // return |
| // } |
| |
| // if (rewrite) { |
| // this.$router.push({ path: '/metrics/index', query: { ip: this.filter } }) |
| // } |
| // const url = '/metrics/ipAddr/?ip=' + filter + '&group=dubbo' |
| // this.$axios.get(url) |
| // .then(response => { |
| // if (!response) { |
| // throw new Error('ServerError') |
| // } |
| // if (!response.data) { |
| // return |
| // } |
| // this.dealNormal(response.data) |
| // this.dealMajor(response.data) |
| // this.dealThreadPoolData(response.data) |
| // }) |
| // .catch(error => { |
| // if (error.message === 'ServerError') { |
| // clearInterval(this.searchTimer) |
| // } |
| // }) |
| // }, |
| // dealThreadPoolData: function (data) { |
| // for (const index in data) { |
| // const metricsDTO = data[index] |
| // if ((metricsDTO.metric).indexOf('threadPool') >= -1) { |
| // const metric = metricsDTO.metric.substring(metricsDTO.metric.lastIndexOf('.') + 1) |
| // if (metric === 'active' || metric === 'current') { |
| // const trending = metric + '_trending' |
| // this.threadPoolData[trending] = this.dealTrending(this.threadPoolData[metric], metricsDTO.value) |
| // } |
| // this.threadPoolData[metric] = metricsDTO.value |
| // } |
| // } |
| // this.threadPoolData.activert = (100 * this.threadPoolData.active / this.threadPoolData.current).toFixed(2) |
| // }, |
| // getKey: function (key) { |
| // return key.substring(key.lastIndexOf('.') + 1) |
| // }, |
| // dealMajor: function (data) { |
| // for (const index in data) { |
| // const metricsDTO = data[index] |
| // if (this.provider.metrics.indexOf(metricsDTO.metric) !== -1) { |
| // const key = this.getKey(metricsDTO.metric) |
| // const data = this.provider[key].series[0].data |
| // if (data.length === 10) { |
| // data.push(metricsDTO.value) |
| // data.shift() |
| // } else { |
| // data.push(metricsDTO.value) |
| // } |
| // this.provider[key].series.data = data |
| // } |
| // if (this.consumer.metrics.indexOf(metricsDTO.metric) !== -1) { |
| // const key = this.getKey(metricsDTO.metric) |
| // const data = this.consumer[key].series[0].data |
| // if (data.length === 10) { |
| // data.push(metricsDTO.value) |
| // data.shift() |
| // } else { |
| // data.push(metricsDTO.value) |
| // } |
| // this.consumer[key].series.data = data |
| // } |
| // } |
| // }, |
| // dealNormal: function (data) { |
| // const serviceMethodMap = {} |
| // for (const index in data) { |
| // const metricsDTO = data[index] |
| // if (metricsDTO.metricLevel === 'NORMAL') { |
| // let metric = metricsDTO.metric + '' |
| // const isProvider = metric.split('.')[1] |
| // metric = isProvider + '.' + metric.substring(metric.lastIndexOf('.') + 1) |
| |
| // let methodMap = serviceMethodMap[metricsDTO.tags.service] |
| // if (!methodMap) { |
| // methodMap = {} |
| // serviceMethodMap[metricsDTO.tags.service] = methodMap |
| // } |
| // let metricMap = methodMap[metricsDTO.tags.method] |
| |
| // if (!metricMap) { |
| // metricMap = {} |
| // serviceMethodMap[metricsDTO.tags.service][metricsDTO.tags.method] = metricMap |
| // } |
| // metricMap[metric] = metricsDTO.value |
| // } |
| // } |
| // this.providerDetails = [] |
| // this.consumerDetails = [] |
| // for (const service in serviceMethodMap) { |
| // for (const method in serviceMethodMap[service]) { |
| // const metricsMap = serviceMethodMap[service][method] |
| // this.addDataToDetails(this.providerDetails, service, method, metricsMap, 'provider') |
| // this.addDataToDetails(this.consumerDetails, service, method, metricsMap, 'consumer') |
| // } |
| // } |
| // }, |
| // addDataToDetails: function (sideDetails, service, method, metricsMap, side) { |
| // if (metricsMap[side + '.qps'] && metricsMap[side + '.success_rate'] && metricsMap[side + '.success_bucket_count']) { |
| // sideDetails.push({ |
| // service: service, |
| // method: method, |
| // qps: metricsMap[side + '.qps'].toFixed(2), |
| // rt: metricsMap[side + '.rt'].toFixed(2), |
| // successRate: metricsMap[side + '.success_rate'], |
| // successCount: metricsMap[side + '.success_bucket_count'] |
| // }) |
| // } |
| // }, |
| // dealTrending: function (oldValue, curValue) { |
| // if (curValue > oldValue) { |
| // return 'trending_up' |
| // } |
| // if (curValue < oldValue) { |
| // return 'trending_down' |
| // } |
| // return '' |
| // }, |
| // setHeaders: function () { |
| // this.headers = [ |
| // { |
| // text: this.$t('service'), |
| // value: 'service' |
| // }, |
| // { |
| // text: this.$t('method'), |
| // value: 'method' |
| // }, |
| // { |
| // text: this.$t('qps'), |
| // value: 'qps' |
| // }, |
| // { |
| // text: this.$t('rt'), |
| // value: 'rt' |
| // }, |
| // { |
| // text: this.$t('successRate'), |
| // value: 'successRate' |
| // } |
| // ] |
| // } |
| // }, |
| // computed: { |
| // area () { |
| // return this.$i18n.locale |
| // } |
| // }, |
| // watch: { |
| // area () { |
| // this.setHeaders() |
| // } |
| // }, |
| // mounted: function () { |
| // this.setHeaders() |
| // let filter = null |
| // const query = this.$route.query |
| // Object.keys(query).forEach(function (key) { |
| // if (key === 'ip') { |
| // filter = query[key] |
| // } |
| // }) |
| // if (filter !== null) { |
| // this.filter = filter |
| // this.searchByIp(this.filter, false) |
| // if (this.searchTimer !== null) { |
| // clearInterval(this.searchTimer) |
| // } |
| // this.searchTimer = setInterval(() => { |
| // this.searchByIp(this.filter, false) |
| // }, 5000) |
| // } |
| // } |
| } |
| </script> |
| |
| <style scoped> |
| .echarts { |
| width: 105%; |
| height: 68px; |
| } |
| |
| </style> |