diff --git a/web/mock/dashboard/cluster_monitor.js b/web/mock/dashboard/cluster_monitor.js new file mode 100644 index 00000000..ec2b7ac0 --- /dev/null +++ b/web/mock/dashboard/cluster_monitor.js @@ -0,0 +1,531 @@ +import { func } from "prop-types"; + +let data = JSON.parse(`{ + "cluster_stats" : { + "indices" : { + "completion" : { + "size_in_bytes" : 0 + }, + "shards" : { + "replication" : 0, + "primaries" : 11, + "total" : 11, + "index" : { + "replication" : { + "avg" : 0, + "min" : 0, + "max" : 0 + }, + "shards" : { + "min" : 1, + "avg" : 1, + "max" : 1 + }, + "primaries" : { + "avg" : 1, + "min" : 1, + "max" : 1 + } + } + }, + "mappings" : { + "field_types" : [ + { + "name" : "alias", + "count" : 3, + "index_count" : 1 + }, + { + "name" : "binary", + "count" : 9, + "index_count" : 1 + }, + { + "name" : "boolean", + "count" : 101, + "index_count" : 6 + }, + { + "name" : "byte", + "count" : 1, + "index_count" : 1 + }, + { + "name" : "date", + "count" : 136, + "index_count" : 10 + }, + { + "name" : "double", + "count" : 103, + "index_count" : 1 + }, + { + "count" : 9, + "name" : "flattened", + "index_count" : 1 + }, + { + "name" : "float", + "count" : 142, + "index_count" : 2 + }, + { + "name" : "geo_point", + "count" : 7, + "index_count" : 1 + }, + { + "name" : "half_float", + "count" : 10, + "index_count" : 2 + }, + { + "name" : "integer", + "count" : 71, + "index_count" : 4 + }, + { + "count" : 20, + "name" : "ip", + "index_count" : 1 + }, + { + "name" : "keyword", + "count" : 1312, + "index_count" : 10 + }, + { + "name" : "long", + "count" : 2623, + "index_count" : 8 + }, + { + "name" : "nested", + "count" : 14, + "index_count" : 5 + }, + { + "name" : "object", + "count" : 2724, + "index_count" : 10 + }, + { + "count" : 121, + "name" : "scaled_float", + "index_count" : 1 + }, + { + "name" : "text", + "count" : 201, + "index_count" : 9 + } + ] + }, + "query_cache" : { + "miss_count" : 31874, + "cache_size" : 0, + "memory_size_in_bytes" : 0, + "total_count" : 31874, + "evictions" : 0, + "hit_count" : 0, + "cache_count" : 0 + }, + "docs" : { + "deleted" : 692, + "count" : 102865 + }, + "fielddata" : { + "memory_size_in_bytes" : 1760, + "evictions" : 0 + }, + "count" : 11, + "store" : { + "size_in_bytes" : 5.2982999E7, + "reserved_in_bytes" : 0 + }, + "analysis" : { + "built_in_filters" : [ ], + "built_in_tokenizers" : [ ], + "tokenizer_types" : [ ], + "analyzer_types" : [ ], + "filter_types" : [ ], + "char_filter_types" : [ ], + "built_in_char_filters" : [ ], + "built_in_analyzers" : [ ] + }, + "segments" : { + "version_map_memory_in_bytes" : 0, + "norms_memory_in_bytes" : 2496, + "file_sizes" : { }, + "max_unsafe_auto_id_timestamp" : -1, + "count" : 36, + "fixed_bit_set_memory_in_bytes" : 14048, + "term_vectors_memory_in_bytes" : 0, + "points_memory_in_bytes" : 0, + "index_writer_memory_in_bytes" : 0, + "memory_in_bytes" : 332776, + "terms_memory_in_bytes" : 109824, + "doc_values_memory_in_bytes" : 202632, + "stored_fields_memory_in_bytes" : 17824 + } + }, + "nodes" : { + "jvm" : { + "max_uptime_in_millis" : 3.1722515E7, + "mem" : { + "heap_max_in_bytes" : 1.073741824E9, + "heap_used_in_bytes" : 3.3389824E8 + }, + "versions" : [ + { + "vm_version" : "15.0.1+9", + "using_bundled_jdk" : true, + "bundled_jdk" : true, + "count" : 1, + "vm_vendor" : "AdoptOpenJDK", + "version" : "15.0.1", + "vm_name" : "OpenJDK 64-Bit Server VM" + } + ], + "threads" : 86 + }, + "process" : { + "open_file_descriptors" : { + "avg" : 402, + "min" : 402, + "max" : 402 + }, + "cpu" : { + "percent" : 0 + } + }, + "network_types" : { + "http_types" : { + "security4" : 1 + }, + "transport_types" : { + "security4" : 1 + } + }, + "os" : { + "available_processors" : 8, + "pretty_names" : [ + { + "pretty_name" : "Mac OS X", + "count" : 1 + } + ], + "names" : [ + { + "name" : "Mac OS X", + "count" : 1 + } + ], + "mem" : { + "used_in_bytes" : 1.6490479616E10, + "free_percent" : 4, + "total_in_bytes" : 1.7179869184E10, + "free_in_bytes" : 6.89389568E8, + "used_percent" : 96 + }, + "allocated_processors" : 8 + }, + "versions" : [ + "7.10.0" + ], + "discovery_types" : { + "zen" : 1 + }, + "plugins" : [ ], + "count" : { + "data_warm" : 1, + "data" : 1, + "data_content" : 1, + "coordinating_only" : 0, + "ingest" : 1, + "master" : 1, + "transform" : 1, + "total" : 1, + "remote_cluster_client" : 1, + "data_cold" : 1, + "voting_only" : 0, + "ml" : 1, + "data_hot" : 1 + }, + "packaging_types" : [ + { + "flavor" : "default", + "count" : 1, + "type" : "tar" + } + ], + "fs" : { + "total_in_bytes" : 1.000240963584E12, + "free_in_bytes" : 9.55349225472E11, + "available_in_bytes" : 9.39232976896E11 + }, + "ingest" : { + "number_of_pipelines" : 1, + "processor_stats" : { + "gsub" : { + "current" : 0, + "time_in_millis" : 0, + "count" : 0, + "failed" : 0 + }, + "script" : { + "current" : 0, + "time_in_millis" : 0, + "count" : 0, + "failed" : 0 + } + } + } + }, + "cluster_uuid" : "JFpIbacZQamv9hkgQEDZ2Q", + "timestamp" : 1.606981605839E12, + "status" : "yellow" + } + }`); + + let nodesStats = JSON.parse(`[ + { + "key" : "node-1", + "doc_count" : 11, + "metrics" : { + "buckets" : [ + { + "key_as_string" : "2020-12-04T09:40:00.000Z", + "key" : 1607074800000, + "doc_count" : 1, + "heap_percent" : { + "value" : 54.0 + }, + "heap_used" : { + "value" : 5.84281136E8 + }, + "index_time" : { + "value" : 5935.0 + }, + "cpu_used" : { + "value" : 0.0 + }, + "search_query_total" : { + "value" : 39044.0 + }, + "index_total" : { + "value" : 5130.0 + }, + "search_query_time" : { + "value" : 7314.0 + } + }, + { + "key_as_string" : "2020-12-04T09:40:30.000Z", + "key" : 1607074830000, + "doc_count" : 3, + "heap_percent" : { + "value" : 63.0 + }, + "heap_used" : { + "value" : 6.776044E8 + }, + "index_time" : { + "value" : 6037.0 + }, + "cpu_used" : { + "value" : 1.0 + }, + "search_query_total" : { + "value" : 39121.0 + }, + "index_total" : { + "value" : 5285.0 + }, + "search_query_time" : { + "value" : 7328.0 + }, + "ds" : { + "value" : 77.0 + }, + "ds1" : { + "value" : 14.0 + }, + "ds3" : { + "value" : 155.0 + }, + "ds4" : { + "value" : 102.0 + } + }, + { + "key_as_string" : "2020-12-04T09:41:00.000Z", + "key" : 1607074860000, + "doc_count" : 3, + "heap_percent" : { + "value" : 64.0 + }, + "heap_used" : { + "value" : 6.92956392E8 + }, + "index_time" : { + "value" : 6181.0 + }, + "cpu_used" : { + "value" : 1.0 + }, + "search_query_total" : { + "value" : 39231.0 + }, + "index_total" : { + "value" : 5426.0 + }, + "search_query_time" : { + "value" : 7343.0 + }, + "ds" : { + "value" : 110.0 + }, + "ds1" : { + "value" : 15.0 + }, + "ds3" : { + "value" : 141.0 + }, + "ds4" : { + "value" : 144.0 + } + }, + { + "key_as_string" : "2020-12-04T09:41:30.000Z", + "key" : 1607074890000, + "doc_count" : 3, + "heap_percent" : { + "value" : 64.0 + }, + "heap_used" : { + "value" : 6.9177856E8 + }, + "index_time" : { + "value" : 6304.0 + }, + "cpu_used" : { + "value" : 1.0 + }, + "search_query_total" : { + "value" : 39339.0 + }, + "index_total" : { + "value" : 5582.0 + }, + "search_query_time" : { + "value" : 7358.0 + }, + "ds" : { + "value" : 108.0 + }, + "ds1" : { + "value" : 15.0 + }, + "ds3" : { + "value" : 156.0 + }, + "ds4" : { + "value" : 123.0 + } + }, + { + "key_as_string" : "2020-12-04T09:42:00.000Z", + "key" : 1607074920000, + "doc_count" : 1, + "heap_percent" : { + "value" : 16.0 + }, + "heap_used" : { + "value" : 1.81371952E8 + }, + "index_time" : { + "value" : 6323.0 + }, + "cpu_used" : { + "value" : 1.0 + }, + "search_query_total" : { + "value" : 39375.0 + }, + "index_total" : { + "value" : 5631.0 + }, + "search_query_time" : { + "value" : 7361.0 + }, + "ds" : { + "value" : 36.0 + }, + "ds1" : { + "value" : 3.0 + }, + "ds3" : { + "value" : 49.0 + }, + "ds4" : { + "value" : 19.0 + } + } + ] + } + } + ]`); + + export default { + 'GET /dashboard/cluster/overview': function(req, res){ + let cluster_stats = data.cluster_stats; + let result = { + elasticsearch:{ + cluster_stats:{ + status: cluster_stats.status, + indices: { + count: cluster_stats.indices.count, + docs: cluster_stats.indices.docs, + shards: cluster_stats.indices.shards, + store: cluster_stats.indices.store, + }, + nodes: { + count:{ + total: cluster_stats.nodes.count.total, + }, + fs: cluster_stats.nodes.fs, + jvm: { + max_uptime_in_millis: cluster_stats.nodes.jvm.max_uptime_in_millis, + mem: cluster_stats.nodes.jvm.mem, + } + } + } + } + }; + res.send(result); + }, + 'GET /dashboard/cluster/nodes_stats': function(req, res) { + // var statsData = [{ + // node_name: nodesStats.source_node.name, + // node_id: nodesStats.source_node.uuid, + // timestamp: nodesStats.timestamp, + // node_stats: { + // jvm: nodesStats.node_stats.jvm, + // process: nodesStats.node_stats.process, + // node_master: nodesStats.node_stats.node_master, + // indices: { + // search: nodesStats.node_stats.indices.search, + // indexing: nodesStats.node_stats.indices.indices, + // }, + // fs: nodesStats.node_stats.fs, + // os: nodesStats.node_stats.os, + // } + // }]; + + res.send({ + nodes_stats: nodesStats + }); + }, + }; \ No newline at end of file diff --git a/web/src/pages/Dashboard/ClusterMonitor.js b/web/src/pages/Dashboard/ClusterMonitor.js index e88f943a..5ef08d22 100644 --- a/web/src/pages/Dashboard/ClusterMonitor.js +++ b/web/src/pages/Dashboard/ClusterMonitor.js @@ -1,7 +1,9 @@ import React, { PureComponent,Fragment } from 'react'; import { connect } from 'dva'; import { formatMessage, FormattedMessage } from 'umi/locale'; -import { Row, Col, Card } from 'antd'; +import { Row, Col, Card,Statistic,Icon, Divider, Skeleton } from 'antd'; +import moment from 'moment'; + import { G2, @@ -11,6 +13,7 @@ import { Tooltip, Legend, } from 'bizcharts'; +import { func } from 'prop-types'; let generateHeapData = (target)=>{ let data = []; @@ -168,8 +171,8 @@ let generateIndexLatencyData = (target)=>{ } componentDidMount() { - let {generateFunc }= this.props; - generateFunc(this); + //let {generateFunc }= this.props; + //generateFunc(this); } render() { //console.log(data.length) @@ -196,7 +199,7 @@ let generateIndexLatencyData = (target)=>{ let pos = `${xname}*${yname}`; return ( ( -// monitor, -// loading: loading.models.monitor, -// })) + +let HealthCircle = (props)=>{ + return ( +
+ ) +} + +let formatter = { + bytes: (value)=>{ + if(null == value || value == ''){ + return "0 Bytes"; + } + var unitArr = new Array("Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"); + var index=0; + var srcsize = parseFloat(value); + index = Math.floor(Math.log(srcsize)/Math.log(1024)); + var size = srcsize/Math.pow(1024,index); + size = size.toFixed(1); + return size + unitArr[index]; + } +} + +@connect(({ clusterMonitor }) => ({ + clusterMonitor +})) +class StatsCharts extends PureComponent { + state = { + heapStats: [], + cpuStats:[], + searchLatency:[], + indexLatency:[], + timeScale: {min: moment().subtract(1, 'h').valueOf(), max: new Date()}, + } + componentDidMount(){ + let {dispatch} = this.props; + let me = this; + setInterval(function(){ + dispatch({ + type: 'clusterMonitor/fetchClusterNodeStats', + callback: ({nodes_stats})=> { + // var heapStats = [], cpuStats=[],searchLatency=[], indexLatency=[]; + // for(let st of nodes_stats){ + // var fields = { + // time: st.timestamp, + // type: st.node_name, + // } + // heapStats.push({ + // ...fields, + // heap_ratio: st.node_stats.jvm.mem.heap_used_percent, + // }); + // cpuStats.push({ + // ...fields, + // cpu_ratio: st.node_stats.process.cpu.percent, + // }); + // } + let nodesStats = nodes_stats; + let nodeCpu = [],nodeHeap=[],nodeSearchLatency=[],nodeIndexLatency=[]; + let now = moment(1607085646112); + for(let ns of nodesStats){ + let i = 0; + for(let bk of ns.metrics.buckets){ + let fields = { + time: now.subtract(300-30*i , 's').valueOf(), //bk.key_as_string, + type: ns.key, + }; + i++; + nodeCpu.push({ + ...fields, + cpu_ratio: bk.cpu_used.value, + }); + nodeHeap.push({ + ...fields, + heap_ratio: bk.heap_percent.value, + }); + nodeSearchLatency.push({ + ...fields, + latency: bk.ds1 ? (bk.ds1.value/bk.ds.value).toFixed(2): 0, + }); + nodeIndexLatency.push({ + ...fields, + latency: bk.ds1 ? (bk.ds4.value/bk.ds3.value).toFixed(2): 0, + }); + } + } + me.setState({ + heapStats: nodeHeap, + cpuStats: nodeCpu, + searchLatency: nodeSearchLatency, + indexLatency: nodeIndexLatency, + timeScale: {min: moment().subtract(1, 'h').valueOf(), max: new Date()}, + }); + } + }); + }, 10000); + } + render(){ + return ( +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ ) + } +} + +@connect(({ clusterMonitor }) => ({ + clusterMonitor +})) class ClusterMonitor extends PureComponent { + state={ + } componentDidMount() { const { dispatch } = this.props; + dispatch({ + type: 'clusterMonitor/fetchClusterOverview', + }); } render() { + let vstyle = { + fontSize: 16, + }; + let descStryle= {color:'#6a717d', fontSize: 12}; + const {clusterMonitor} = this.props; + console.log(clusterMonitor); + let clusterStats = {}; + if(clusterMonitor.elasticsearch){ + let rawStats = clusterMonitor.elasticsearch.cluster_stats; + clusterStats = { + status: rawStats.status, + nodes_count: rawStats.nodes.count.total, + disk_avaiable: (rawStats.nodes.fs.available_in_bytes/rawStats.nodes.fs.total_in_bytes * 100).toFixed(2) + "%", + disk_desc: formatter.bytes(rawStats.nodes.fs.available_in_bytes) + "/" + formatter.bytes(rawStats.nodes.fs.total_in_bytes), + jvm_mem: (rawStats.nodes.jvm.mem.heap_used_in_bytes/rawStats.nodes.jvm.mem.heap_max_in_bytes * 100).toFixed(2) + "%", + jvm_desc: formatter.bytes(rawStats.nodes.jvm.mem.heap_used_in_bytes) + "/" + formatter.bytes(rawStats.nodes.jvm.mem.heap_max_in_bytes), + shards_count: rawStats.indices.shards.total, + shards_desc: "主:" + rawStats.indices.shards.primaries + ",从:" + rawStats.indices.shards.replication, + docs: rawStats.indices.docs.count, + indices_count: rawStats.indices.count, + online_duration: moment.duration(rawStats.nodes.jvm.max_uptime_in_millis).humanize(), + }; + } return (
- - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + } /> + + + + + + ({clusterStats.disk_desc})
+ } /> + + + ({clusterStats.jvm_desc}) + } /> + + + ({clusterStats.shards_desc}) + } /> + + + + + + + + + ); } diff --git a/web/src/pages/Dashboard/models/cluster.js b/web/src/pages/Dashboard/models/cluster.js new file mode 100644 index 00000000..660cd809 --- /dev/null +++ b/web/src/pages/Dashboard/models/cluster.js @@ -0,0 +1,32 @@ +import {getClusterOverview, getClusterNodeStats} from "@/services/dashboard"; + +export default { + namespace: 'clusterMonitor', + state: { + + }, + effects:{ + *fetchClusterOverview({callback}, {call, put}){ + let clusterData = yield call(getClusterOverview); + yield put({type: 'saveData', payload: clusterData}) + if(callback && typeof callback == 'function'){ + callback(clusterData); + } + }, + *fetchClusterNodeStats({callback}, {call, put}){ + let nodesStats = yield call(getClusterNodeStats); + //yield put({type: 'saveData', payload: nodesStats}) + if(callback && typeof callback == 'function'){ + callback(nodesStats); + } + } + }, + reducers:{ + saveData(state, {payload}){ + return { + ...state, + ...payload + }; + }, + } +}; \ No newline at end of file diff --git a/web/src/services/dashboard.js b/web/src/services/dashboard.js new file mode 100644 index 00000000..966cbfd0 --- /dev/null +++ b/web/src/services/dashboard.js @@ -0,0 +1,9 @@ +import request from '@/utils/request'; + +export async function getClusterOverview(){ + return request('/dashboard/cluster/overview'); +} + +export async function getClusterNodeStats(){ + return request('/dashboard/cluster/nodes_stats'); +} \ No newline at end of file