| <!-- |
| - 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;" /> |
| <mini-chart |
| title="qps(ms)" |
| :sub-title="majorDataMap.provider.qps" |
| :icon="majorDataMap.provider.qps_trending" |
| :data="dataset.monthVisit" |
| :chart-color="color.blue.base" |
| type="line" |
| ></mini-chart> |
| <hr style="height:1px;border:none;border-top:1px solid #ADADAD;" /> |
| <mini-chart |
| title="rt(ms)" |
| :sub-title="majorDataMap.provider.rt" |
| :icon="majorDataMap.provider.rt_trending" |
| :data="dataset.monthVisit" |
| :chart-color="color.blue.base" |
| type="line" |
| class="minichart" |
| ></mini-chart> |
| <hr style="height:1px;border:none;border-top:1px solid #ADADAD;" /> |
| <mini-chart |
| title="success rate" |
| :sub-title="majorDataMap.provider.success_rate" |
| :icon="majorDataMap.provider.success_rate_trending" |
| :data="dataset.monthVisit" |
| :chart-color="color.blue.base" |
| type="line" |
| ></mini-chart> |
| <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;" /> |
| <mini-chart |
| title="qps(ms)" |
| :sub-title="majorDataMap.consumer.qps" |
| :icon="majorDataMap.consumer.qps_trending" |
| :data="dataset.monthVisit" |
| :chart-color="color.blue.base" |
| type="line" |
| ></mini-chart> |
| <hr style="height:1px;border:none;border-top:1px solid #ADADAD;" /> |
| <mini-chart |
| title="rt(ms)" |
| :sub-title="majorDataMap.consumer.rt" |
| :icon="majorDataMap.consumer.rt_trending" |
| :data="dataset.monthVisit" |
| :chart-color="color.blue.base" |
| type="line" |
| ></mini-chart> |
| <hr style="height:1px;border:none;border-top:1px solid #ADADAD;" /> |
| <mini-chart |
| title="success rate" |
| :sub-title="majorDataMap.consumer.success_rate" |
| :icon="majorDataMap.consumer.success_rate_trending" |
| :data="dataset.monthVisit" |
| :chart-color="color.blue.base" |
| type="line" |
| ></mini-chart> |
| <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-layout> |
| </v-container> |
| </template> |
| |
| <script> |
| import EChart from '@/util/echart' |
| import Material from 'vuetify/es5/util/colors' |
| import MiniChart from '@/components/public/MiniChart' |
| import Breadcrumb from '@/components/public/Breadcrumb' |
| import Search from '@/components/public/Search' |
| import { |
| campaignData, |
| locationData, |
| StackData, |
| SinData |
| } from '@/api/chart' |
| |
| const shortMonth = [ |
| 1, 2, 3, 4, 5, 6 |
| ] |
| |
| export default { |
| |
| name: 'ServiceMetrics', |
| components: { |
| MiniChart, |
| EChart, |
| Breadcrumb, |
| Search |
| }, |
| data () { |
| return { |
| threadPoolData: { |
| 'core': 0, |
| 'max': 0, |
| 'current': 0, |
| 'current_trending': '', |
| 'active': 0, |
| 'active_trending': '', |
| 'activert': 0 |
| }, |
| echartMap: { |
| 'provider': [{ |
| 'timestamp': 0, |
| 'qps': 0, |
| 'tt': 0, |
| 'success_rate': 0 |
| }], |
| 'consumer': [{ |
| 'timestamp': 0, |
| 'qps': 0, |
| 'tt': 0, |
| 'success_rate': 0 |
| }] |
| }, |
| majorDataMap: { |
| provider: { |
| qps: '0', |
| qps_trending: '', |
| rt: '0', |
| rt_trending: '', |
| success_rate: '0%', |
| success_rate_trending: '' |
| }, |
| consumer: { |
| qps: '0', |
| qps_trending: '', |
| rt: '0', |
| rt_trending: '', |
| success_rate: '0%', |
| success_rate_trending: '' |
| }, |
| threadPool: {} |
| }, |
| selectedTab: 'tab-1', |
| filter: '', |
| headers: [], |
| providerDetails: [ |
| { |
| service: 'a.b.c.d', |
| method: 'aaaa~ICS', |
| qps: '0.58', |
| rt: '111', |
| success_rate: '100%' |
| }, |
| { |
| service: 'a.b.c.f', |
| method: 'bbbb~ICS', |
| qps: '0.87', |
| rt: '120', |
| success_rate: '90%' |
| } |
| |
| ], |
| consumerDetails: [], |
| option: null, |
| dataset: { |
| sinData: SinData, |
| monthVisit: shortMonth.map(m => { |
| return { |
| 'time': m, |
| 'Value': Math.floor(Math.random() * 1000) + 200 |
| } |
| }), |
| campaign: campaignData, |
| location: locationData, |
| stackData: StackData |
| }, |
| color: Material, |
| breads: [ |
| { |
| text: 'metrics', |
| href: '' |
| } |
| ] |
| |
| } |
| }, |
| /* |
| * */ |
| methods: { |
| submit: function () { |
| this.vv = 20 |
| //这里变不了我就很迷了 |
| this.dataset.monthVisit = [{'time': 1, 'Value': 200}] |
| this.filter = this.filter.trim() |
| this.searchByIp(this.filter) |
| }, |
| setRandomValue: function (data) { |
| for (let i in data) { |
| data[i]['value'] = Math.floor(Math.random() * 1000) + 200 |
| } |
| return data |
| }, |
| searchByIp: function (filter) { |
| //TODO 到时候记得把filter塞进来 |
| let url = '/metrics/ipAddr/?ip' + '=127.0.0.1' + '&group=dubbo' |
| this.$axios.get(url) |
| .then(response => { |
| if (!response.data) { |
| return |
| } |
| this.dealNormal(response.data) |
| this.dealMajor(response.data) |
| this.dealThreadPoolData(response.data) |
| }) |
| }, |
| dealThreadPoolData: function (data) { |
| for (let index in data) { |
| let metricsDTO = data[index] |
| if ((metricsDTO['metric']).indexOf('threadPool') >= -1) { |
| let metric = metricsDTO['metric'].substring(metricsDTO['metric'].lastIndexOf('.') + 1) |
| if (metric === 'active' || metric === 'current') { |
| let 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) |
| }, |
| dealMajor: function (data) { |
| for (let index in data) { |
| let metricsDTO = data[index] |
| if (metricsDTO['metricLevel'] === 'MAJOR' && (metricsDTO['metric']).indexOf('threadPool') === -1) { |
| let metric = metricsDTO['metric'] + '' |
| let provider = metric.split('.')[1] |
| metric = metric.substring(metric.lastIndexOf('.') + 1) |
| this.dealEchartData(metricsDTO, provider, metric) |
| if (typeof metricsDTO.value !== 'string') { |
| metricsDTO.value = metricsDTO.value.toFixed(2) |
| } |
| if (this.majorDataMap[provider][metric]) { |
| let trending = metric + '_trending' |
| this.majorDataMap[provider][trending] = this.dealTrending(this.majorDataMap[provider][metric], metricsDTO.value) |
| this.majorDataMap[provider][metric] = metricsDTO.value |
| } |
| } |
| } |
| }, |
| dealEchartData: function (metricsDTO, provider, metric) { |
| //这一块 |
| let timestamp = metricsDTO['timestamp'] |
| let arr = this.echartMap[provider] |
| let lastTime = arr[arr.length - 1]['timestamp'] |
| if (timestamp > lastTime) { |
| arr.push({ |
| 'timestamp': timestamp, |
| metric: metricsDTO['value'] |
| }) |
| if (arr.length > 10) { |
| arr.shift() |
| } |
| } else { |
| arr[arr.length - 1][metric] = metricsDTO['value'] |
| } |
| }, |
| dealNormal: function (data) { |
| let serviceMethodMap = {} |
| for (let index in data) { |
| let metricsDTO = data[index] |
| if (metricsDTO['metricLevel'] === 'NORMAL') { |
| let metric = metricsDTO['metric'] + '' |
| let 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 (let service in serviceMethodMap) { |
| for (let method in serviceMethodMap[service]) { |
| let 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' |
| } |
| ] |
| } |
| }, |
| mounted: function () { |
| this.setHeaders() |
| setInterval(() => { |
| this.submit() |
| }, 5000) |
| } |
| } |
| </script> |
| |
| <style scoped> |
| |
| </style> |