fix cluster metrics ui

This commit is contained in:
medcl 2021-03-05 00:23:49 +08:00
parent 21301f52e8
commit 494bb8cdf2
6 changed files with 249 additions and 143 deletions

View File

@ -18,7 +18,7 @@ export default [
authority: ['admin', 'user'],
routes: [
// cluster
{ path: '/', redirect: '/cluster/overview' },
{ path: '/', redirect: '/cluster/overview/' },
{
path: '/cluster',
name: 'cluster',
@ -26,24 +26,35 @@ export default [
routes: [
// { path: '/', redirect: '/platform/gateway' },
{
path: '/cluster/overview',
path: '/cluster/overview/',
name: 'overview',
component: './Cluster/Overview',
}, {
}, {
path: '/cluster/overview/:elasticsearch',
name: 'overview',
component: './Cluster/Overview',
hideInMenu: true,
},
{
path: '/cluster/monitoring/:name',
name: 'cluster',
component: './Cluster/ClusterMonitor',
hideInMenu: true,
}, {
path: '/cluster/metrics',
path: '/cluster/metrics/',
name: 'monitoring',
component: './Cluster/Metrics',
}, {
path: '/cluster/logging',
path: '/cluster/metrics/:elasticsearch',
name: 'monitoring',
component: './Cluster/Metrics',
hideInMenu: true,
}, {
path: '/cluster/logs/',
name: 'logging',
component: './Cluster/SearchMonitor',
},{
path: '/cluster/settings',
path: '/cluster/settings/',
name: 'settings',
component: './Cluster/Settings/Base',
routes: [

View File

@ -6,10 +6,25 @@ import styles from './index.less';
import RightContent from './RightContent';
import DropdownSelect from './DropdownSelect'
import router from "umi/router";
const path=require('path');
export default class GlobalHeader extends PureComponent {
componentWillUnmount() {
constructor(props) {
super(props);
}
componentDidMount() {
}
componentWillUnmount() {
this.triggerResizeEvent.cancel();
}
/* eslint-disable*/
@Debounce(600)
triggerResizeEvent() {
@ -44,7 +59,17 @@ export default class GlobalHeader extends PureComponent {
onChange={(item)=>{
this.props.handleSaveGlobalState({
selectedCluster: item
})
});
const path1=this.props.location.pathname
if (path1[path1.length-1] !=='/'){
const currentPath=path.dirname(path1);
router.replace(currentPath+'/'+item.id);
}else{
router.replace(path1+item.id);
}
//location.reload()
}}
size={56}
fetchData={

View File

@ -13,6 +13,7 @@ export default {
clusterVisible: true,
clusterList: [],
selectedCluster: {name:"Select cluster", id: ""},
selectedClusterID: "",
},
effects: {
@ -122,6 +123,7 @@ export default {
return {
...state,
selectedCluster: state.clusterList[idx],
selectedClusterID: state.clusterList[idx].id,
}
}
return state;

View File

@ -4,6 +4,7 @@ import {formatMessage} from 'umi/locale';
import {Button, Card, Col, DatePicker, Dropdown, Icon, Input, InputNumber, Row, Select, Statistic} from 'antd';
import moment from 'moment';
import {DateTime} from 'luxon';
import router from "umi/router";
import numeral from 'numeral';
@ -21,6 +22,9 @@ import {
} from "@elastic/charts";
import styles from './Metrics.less';
import { Spin, Alert } from 'antd';
const {RangePicker} = DatePicker;
@ -140,7 +144,8 @@ const vstyle = {
@connect(({clusterMonitor,global}) => ({
clusterMonitor,
selectedCluster: global.selectedCluster
selectedCluster: global.selectedCluster,
clusterList: global.clusterList
}))
class ClusterMonitor extends PureComponent {
@ -151,6 +156,8 @@ class ClusterMonitor extends PureComponent {
}
state = {
spinning: false,
clusterID:null,
timeRange: {
min: moment().subtract(1, 'h').toISOString(),
max: moment().toISOString()
@ -158,7 +165,24 @@ class ClusterMonitor extends PureComponent {
lastSeconds: 3600,
qsVisible: false,
}
componentWillReceiveProps(newProps) {
}
fetchData = () => {
console.log("fetching data ing."+this.state.clusterID)
if (this.state.clusterID===undefined||this.state.clusterID===""||this.state.clusterID===null){
return
}
this.setState({
spinning:true,
})
fetchDataCount++;
//console.log(fetchDataCount, moment().diff(startTime)/1000);
const {dispatch} = this.props;
@ -184,24 +208,58 @@ class ClusterMonitor extends PureComponent {
timeMask = 'YY-MM-DD'
}
this.setState({timeScale: {min: timeRange.min, max: timeRange.max, mask: timeMask}});
// console.log(this.props.selectedCluster)
dispatch({
type: 'clusterMonitor/fetchClusterMetrics',
payload: {
timeRange: timeRange,
cluster_id:this.props.selectedCluster?this.props.selectedCluster.id:''
cluster_id:this.state.clusterID
},
});
}).then(()=>{
this.setState({
spinning:false,
})
})
}
componentWillUnmount() {
clearInterval(tv1);
}
componentDidUpdate(prevProps, prevState, snapshot) {
// console.log(this.props.selectedCluster)
// console.log(this.state.clusterID)
if (this.props.selectedCluster.id!==this.state.clusterID){
console.log("cluster changed")
this.setState({ clusterID:this.props.selectedCluster.id }, () => {
//TODO 处理 cancel 事件,先把当前还在执行中的请求结束,避免更新完成之后,被晚到的之前的请求给覆盖了。
this.fetchData();
});
}
}
componentDidMount() {
const {match, location} = this.props;
const queryESID=this.props.match.params.elasticsearch;
if (queryESID !== null&&queryESID !== undefined){
this.state.clusterID=queryESID
const {dispatch} = this.props;
dispatch({
type: 'global/changeClusterById',
payload: {
id: queryESID
}
})
}else{
//alert("cluster ID is not set");
return
}
console.log("selectedCluster:"+this.state.clusterID)
let min = location.query.start || '2020-12-10 15:00';
let max = location.query.end || '2020-12-10 16:00';
@ -221,7 +279,8 @@ class ClusterMonitor extends PureComponent {
// tv1 = setInterval(()=>{
// this.fetchData();
// }, 10000);
this.autoRefresh();
//this.autoRefresh();
}
autoRefresh(durationInSeconds) {
@ -427,7 +486,7 @@ class ClusterMonitor extends PureComponent {
// <Menu.Item key="5"> */}
<Input.Group compact>
<Button style={{cursor: "default"}}>刷新间隔</Button>
<InputNumber min={1} defaultValue={10} ref={el => this.refreshNum = el}/>
<InputNumber min={-1} defaultValue={-1} ref={el => this.refreshNum = el}/>
<Select defaultValue="seconds" ref={el => this.refreshUnit = el}>
<Select.Option value="seconds"></Select.Option>
<Select.Option value="minutes"></Select.Option>
@ -443,137 +502,140 @@ class ClusterMonitor extends PureComponent {
);
return (
<div>
<div style={{background: "#fff", padding: "5px", marginBottom: 5}}>
<Input.Group compact>
<Dropdown overlay={menu}
onVisibleChange={this.handleQSVisibleChange}
visible={this.state.qsVisible}
>
<Button>
快速选择 <Icon type="clock-circle"/>
<Spin spinning={this.state.spinning} tip="Loading...">
<div>
<div style={{background: "#fff", padding: "5px", marginBottom: 5}}>
<Input.Group compact>
<Dropdown overlay={menu}
onVisibleChange={this.handleQSVisibleChange}
visible={this.state.qsVisible}
>
<Button>
快速选择 <Icon type="clock-circle"/>
</Button>
</Dropdown>
<RangePicker
showTime={{format: 'HH:mm'}}
format="YYYY-MM-DD HH:mm"
placeholder={['开始时间', '结束时间']}
defaultValue={[moment().subtract(1, 'h'), moment()]}
value={this.state.pickerValue}
onChange={this.onTimeChange}
onOk={this.onTimeOk}
/>
<Button type="primary" onClick={this.fetchData}>
刷新
</Button>
</Dropdown>
<RangePicker
showTime={{format: 'HH:mm'}}
format="YYYY-MM-DD HH:mm"
placeholder={['开始时间', '结束时间']}
defaultValue={[moment().subtract(1, 'h'), moment()]}
value={this.state.pickerValue}
onChange={this.onTimeChange}
onOk={this.onTimeOk}
/>
<Button type="primary" onClick={this.fetchData}>
刷新
</Button>
</Input.Group>
</Input.Group>
</div>
<Card
//title={this.state.clusterID?this.state.clusterID:''}
style={{marginBottom: 5}}>
<Row>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="集群名称" value={clusterStats.cluster_name}/>
</Col>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="在线时长" value={clusterStats.uptime}/>
</Col>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="集群版本" value={clusterStats.version}/>
</Col>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="健康情况" value={clusterStats.status}
prefix={<HealthCircle color={clusterStats.status}/>}/>
</Col>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="节点数" value={clusterStats.nodes_count}/>
</Col>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="索引数" value={clusterStats.indices_count}/>
</Col>
<Col md={3} xs={4}>
<Statistic valueStyle={vstyle} title="分片数"
value={clusterStats.primary_shards + '/' + clusterStats.unassigned_shards + '/' + clusterStats.total_shards}/>
</Col>
<Col md={3} xs={4}>
<Statistic valueStyle={vstyle} title="文档数" value={clusterStats.document_count}/>
</Col>
<Col md={3} xs={4}>
<Statistic valueStyle={vstyle} title="存储空间"
value={clusterStats.used_store_bytes + '/' + clusterStats.max_store_bytes}/>
</Col>
<Col md={3} xs={4}>
<Statistic valueStyle={vstyle} title="JVM 内存"
value={clusterStats.used_jvm_bytes + '/' + clusterStats.max_jvm_bytes}/>
</Col>
</Row>
</Card>
{
Object.keys(clusterMetrics).map((e, i) => {
let axis = clusterMetrics[e].axis
let lines = clusterMetrics[e].lines
let disableHeaderFormat = false
let headerUnit = ""
return (
<div className={styles.vizChartContainer}>
<Chart size={[, 200]} className={styles.vizChartItem}>
<Settings theme={theme} showLegend legendPosition={Position.Top}
tooltip={{
headerFormatter: disableHeaderFormat
? undefined
: ({value}) => `${formatter.full_dates(value)}${headerUnit ? ` ${headerUnit}` : ''}`,
}}
debug={false}/>
<Axis id="{e}-bottom" position={Position.Bottom} showOverlappingTicks
labelFormat={formatter.dates}
tickFormat={formatter.dates}
/>
{
axis.map((item) => {
return <Axis
id={e + '-' + item.id}
showGridLines={item.showGridLines}
groupId={item.group}
title={formatMessage({id: 'dashboard.charts.title.' + e + '.axis.' + item.title})}
position={item.position}
ticks={item.ticks}
labelFormat={getFormatter(item.formatType, item.labelFormat)}
tickFormat={getFormatter(item.formatType, item.tickFormat)}
/>
})
}
{
lines.map((item) => {
return <LineSeries
id={item.metric.label}
groupId={item.metric.group}
timeZone={timezone}
xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear}
xAccessor={0}
tickFormat={getFormatter(item.metric.formatType, item.metric.tickFormat, item.metric.units)}
yAccessors={[1]}
data={item.data}
curve={CurveType.CURVE_MONOTONE_X}
/>
})
}
</Chart>
</div>
)
})
}
</div>
<Card
// title={this.props.selectedCluster?this.props.selectedCluster.name:''}
style={{marginBottom: 5}}>
<Row>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="集群名称" value={clusterStats.cluster_name}/>
</Col>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="在线时长" value={clusterStats.uptime}/>
</Col>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="集群版本" value={clusterStats.version}/>
</Col>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="健康情况" value={clusterStats.status}
prefix={<HealthCircle color={clusterStats.status}/>}/>
</Col>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="节点数" value={clusterStats.nodes_count}/>
</Col>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="索引数" value={clusterStats.indices_count}/>
</Col>
<Col md={3} xs={4}>
<Statistic valueStyle={vstyle} title="分片数"
value={clusterStats.primary_shards + '/' + clusterStats.unassigned_shards + '/' + clusterStats.total_shards}/>
</Col>
<Col md={3} xs={4}>
<Statistic valueStyle={vstyle} title="文档数" value={clusterStats.document_count}/>
</Col>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="存储空间"
value={clusterStats.used_store_bytes + '/' + clusterStats.max_store_bytes}/>
</Col>
<Col md={2} xs={4}>
<Statistic valueStyle={vstyle} title="JVM 内存"
value={clusterStats.used_jvm_bytes + '/' + clusterStats.max_jvm_bytes}/>
</Col>
</Row>
</Card>
{
Object.keys(clusterMetrics).map((e, i) => {
let axis = clusterMetrics[e].axis
let lines = clusterMetrics[e].lines
let disableHeaderFormat = false
let headerUnit = ""
return (
<div className={styles.vizChartContainer}>
<Chart size={[, 200]} className={styles.vizChartItem}>
<Settings theme={theme} showLegend legendPosition={Position.Top}
tooltip={{
headerFormatter: disableHeaderFormat
? undefined
: ({value}) => `${formatter.full_dates(value)}${headerUnit ? ` ${headerUnit}` : ''}`,
}}
debug={false}/>
<Axis id="{e}-bottom" position={Position.Bottom} showOverlappingTicks
labelFormat={formatter.dates}
tickFormat={formatter.dates}
/>
{
axis.map((item) => {
return <Axis
id={e + '-' + item.id}
showGridLines={item.showGridLines}
groupId={item.group}
title={formatMessage({id: 'dashboard.charts.title.' + e + '.axis.' + item.title})}
position={item.position}
ticks={item.ticks}
labelFormat={getFormatter(item.formatType, item.labelFormat)}
tickFormat={getFormatter(item.formatType, item.tickFormat)}
/>
})
}
{
lines.map((item) => {
return <LineSeries
id={item.metric.label}
groupId={item.metric.group}
timeZone={timezone}
xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear}
xAccessor={0}
tickFormat={getFormatter(item.metric.formatType, item.metric.tickFormat, item.metric.units)}
yAccessors={[1]}
data={item.data}
curve={CurveType.CURVE_MONOTONE_X}
/>
})
}
</Chart>
</div>
)
})
}
</div>
</Spin>
);
}
}

View File

@ -24,6 +24,7 @@ let HealthCircle = (props)=>{
}))
class Overview extends React.Component {
state = {
data: [{id:"JFpIbacZQamv9hkgQEDZ2Q", name:"single-es", endpoint:"http://localhost:9200", health: "green", version: "7.10.0", uptime:"320883955"}]
}
@ -142,6 +143,10 @@ class Overview extends React.Component {
render() {
// useEffect(() => {
// console.log('Listening: ', name);
// }, [name]);
return (
<div>
<Button type="primary" onClick={this.handleChangeClusterById}>change cluster</Button>

View File

@ -19,6 +19,7 @@ export default {
yield put({type: 'saveData', payload: clusterMetrics})
if(callback && typeof callback == 'function'){
callback(clusterMetrics);
console.log("finished call:"+params.cluster_id);
}
},
*fetchClusterNodeStats({callback}, {call, put}){