|
@@ -0,0 +1,199 @@
|
|
|
|
|
+import React, { PureComponent } from 'react';
|
|
|
|
|
+import styles from './MetricsCard.less';
|
|
|
|
|
+import { connect, history } from 'umi';
|
|
|
|
|
+import { PageHeader, Statistic, Radio } from 'antd';
|
|
|
|
|
+import { Chart, Line, Point, Tooltip, Axis } from "bizcharts";
|
|
|
|
|
+import moment from 'moment';
|
|
|
|
|
+
|
|
|
|
|
+const types = ['cpu', 'memory'];
|
|
|
|
|
+const sourceNames = {
|
|
|
|
|
+ 'cluster': '集群',
|
|
|
|
|
+ 'node': '节点',
|
|
|
|
|
+ 'pod': 'POD',
|
|
|
|
|
+ 'environment': '环境',
|
|
|
|
|
+ 'application': '应用'
|
|
|
|
|
+}
|
|
|
|
|
+const typeDivideFactor = {
|
|
|
|
|
+ cpu: 1000000000,
|
|
|
|
|
+ memory: 1000,
|
|
|
|
|
+}
|
|
|
|
|
+const typePoint = {
|
|
|
|
|
+ cpu: 3,
|
|
|
|
|
+ memory: 2,
|
|
|
|
|
+}
|
|
|
|
|
+const axisName = {
|
|
|
|
|
+ cpu: '核数',
|
|
|
|
|
+ memory: 'MB',
|
|
|
|
|
+}
|
|
|
|
|
+const typeName = {
|
|
|
|
|
+ cpu: 'CPU',
|
|
|
|
|
+ memory: '内存'
|
|
|
|
|
+}
|
|
|
|
|
+@connect(({ metrics }) => ({
|
|
|
|
|
+ metrics
|
|
|
|
|
+}))
|
|
|
|
|
+export default class MetricsCard extends PureComponent {
|
|
|
|
|
+ state = {
|
|
|
|
|
+ types: ['cpu', 'memory'],
|
|
|
|
|
+ currentData: {},
|
|
|
|
|
+ data: {},
|
|
|
|
|
+ interval: {},
|
|
|
|
|
+ }
|
|
|
|
|
+ componentDidMount() {
|
|
|
|
|
+ if (this.state.currentData['cpu'] == null || this.state.currentData['cpu'].length) {
|
|
|
|
|
+ this.fetchCurrent(this.props.metricsSourceValue);
|
|
|
|
|
+ }
|
|
|
|
|
+ this.state.types.forEach(type => {
|
|
|
|
|
+ if (this.state.data[type] == null || this.state.data[type].length) {
|
|
|
|
|
+ this.fetchBetween(type, this.props.metricsSourceValue);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ this.currentTimeout = setInterval(() => {
|
|
|
|
|
+ this.fetchCurrent(this.props.metricsSourceValue);
|
|
|
|
|
+ }, 60000);
|
|
|
|
|
+ this.state.types.forEach(type => {
|
|
|
|
|
+ this.fetchBetween(type, this.props.metricsSourceValue);
|
|
|
|
|
+ if (!this.timeout) {
|
|
|
|
|
+ this.timeout = {}
|
|
|
|
|
+ }
|
|
|
|
|
+ this.timeout[type] = setInterval(() => {
|
|
|
|
|
+ this.fetchBetween(type, this.props.metricsSourceValue);
|
|
|
|
|
+ }, 60000);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ fetchCurrent(source) {
|
|
|
|
|
+ if (source == null || source === 'undefined') {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ this.props.dispatch({
|
|
|
|
|
+ type: 'metrics/getCurrent',
|
|
|
|
|
+ payload: {
|
|
|
|
|
+ metricsSource: this.props.metricsSource,
|
|
|
|
|
+ metricsSourceValue: source,
|
|
|
|
|
+ callback: (response) => {
|
|
|
|
|
+ if (response && response.code == 0) {
|
|
|
|
|
+ let currentData = {};
|
|
|
|
|
+ this.state.types.forEach(type => {
|
|
|
|
|
+ let metric = response.result.filter(item => item.metricsType == type)[0];
|
|
|
|
|
+ currentData[type] = metric.metricsTypeValue;
|
|
|
|
|
+ });
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ currentData
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ fetchBetween(type, source) {
|
|
|
|
|
+ if (source == null || source === 'undefined') {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ let now = moment();
|
|
|
|
|
+ this.props.dispatch({
|
|
|
|
|
+ type: 'metrics/getBetween',
|
|
|
|
|
+ payload: {
|
|
|
|
|
+ metricsSource: this.props.metricsSource,
|
|
|
|
|
+ metricsSourceValue: source,
|
|
|
|
|
+ metricsType: type,
|
|
|
|
|
+ startTime: now.clone().subtract(this.state.interval[type] ? +this.state.interval[type] : 10, 'm').valueOf(),
|
|
|
|
|
+ endTime: now.valueOf(),
|
|
|
|
|
+ callback: (response) => {
|
|
|
|
|
+ if (response && response.code == 0) {
|
|
|
|
|
+ let data = response.result.map(item => {
|
|
|
|
|
+ return {
|
|
|
|
|
+ ...item,
|
|
|
|
|
+ time: item.metricsTime,
|
|
|
|
|
+ value: ((+item.metricsTypeValue) / typeDivideFactor[type]).toFixed(typePoint[type]),
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ data: {
|
|
|
|
|
+ ...this.state.data,
|
|
|
|
|
+ [type]: data,
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ componentWillReceiveProps(props) {
|
|
|
|
|
+ if (this.props.metricsSourceValue != props.metricsSourceValue) {
|
|
|
|
|
+ console.log(props.metricsSourceValue)
|
|
|
|
|
+ this.fetchCurrent(props.metricsSourceValue);
|
|
|
|
|
+ this.state.types.forEach(type => {
|
|
|
|
|
+ this.fetchBetween(type, props.metricsSourceValue);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ componentWillUnmount() {
|
|
|
|
|
+ types.forEach(type => {
|
|
|
|
|
+ clearInterval(this.timeout[type]);
|
|
|
|
|
+ });
|
|
|
|
|
+ clearInterval(this.currentTimeout);
|
|
|
|
|
+ }
|
|
|
|
|
+ changeInterval(type, e) {
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ interval: {
|
|
|
|
|
+ ...this.state.interval,
|
|
|
|
|
+ [type]: e.target.value,
|
|
|
|
|
+ }
|
|
|
|
|
+ }, () => {
|
|
|
|
|
+ this.fetchBetween(type, this.props.metricsSourceValue);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ render() {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <PageHeader
|
|
|
|
|
+ title={this.props.showTitle ? this.props.metricsSourceValue : ''}
|
|
|
|
|
+ subTitle={this.props.showTitle ? sourceNames[this.props.metricsSource] : ''}
|
|
|
|
|
+ >
|
|
|
|
|
+ <div className={styles.cardBody}>
|
|
|
|
|
+ <div className={styles.statistic}>
|
|
|
|
|
+ <Statistic title="CPU" suffix="core" value={((+this.state.currentData['cpu'])/1000000000).toFixed(3)}></Statistic>
|
|
|
|
|
+ <Statistic title="内存" suffix="MB" value={((+this.state.currentData['memory'])/1000).toFixed(2)}></Statistic>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div className={styles.charts}>
|
|
|
|
|
+ {types.map(type => {
|
|
|
|
|
+ const scale = {
|
|
|
|
|
+ time: {
|
|
|
|
|
+ type: 'time',
|
|
|
|
|
+ alias: '时间',
|
|
|
|
|
+ mask: 'HH:mm',
|
|
|
|
|
+ },
|
|
|
|
|
+ value: {
|
|
|
|
|
+ type: 'linear',
|
|
|
|
|
+ alias: axisName[type],
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div className={styles.chart} key={type}>
|
|
|
|
|
+ <div className={styles.head}>{`${typeName[type]}使用情况`}</div>
|
|
|
|
|
+ <div className={styles.radio}>
|
|
|
|
|
+ <Radio.Group className={styles.radio} value={this.state.interval[type] ? this.state.interval[type] : "10"} onChange={(e) => this.changeInterval(type, e)} defaultValue="10">
|
|
|
|
|
+ <Radio.Button value="10">10min</Radio.Button>
|
|
|
|
|
+ <Radio.Button value="30">30min</Radio.Button>
|
|
|
|
|
+ <Radio.Button value="60">1h</Radio.Button>
|
|
|
|
|
+ <Radio.Button value="240">4h</Radio.Button>
|
|
|
|
|
+ </Radio.Group>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <Chart
|
|
|
|
|
+ scale={scale}
|
|
|
|
|
+ autoFit
|
|
|
|
|
+ height={200}
|
|
|
|
|
+ data={this.state.data[type]}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Point position="time*value" shape='circle'></Point>
|
|
|
|
|
+ <Line shape="smooth" position="time*value" />
|
|
|
|
|
+ <Tooltip shared showCrosshairs/>
|
|
|
|
|
+ <Axis />
|
|
|
|
|
+ </Chart>
|
|
|
|
|
+ </div>)
|
|
|
|
|
+ })}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </PageHeader>
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+}
|