Add broker statistics

This commit is contained in:
Thomas Nordquist
2019-01-22 19:54:36 +01:00
parent a86871b161
commit 37694d38b0
13 changed files with 170 additions and 37 deletions

6
app/package-lock.json generated
View File

@@ -4934,6 +4934,12 @@
"throttleit": "0.0.2" "throttleit": "0.0.2"
} }
}, },
"number-abbreviate": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/number-abbreviate/-/number-abbreviate-2.0.0.tgz",
"integrity": "sha1-6cstGNuADhU88HKClVPEr+DfeJg=",
"dev": true
},
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",

View File

@@ -16,6 +16,7 @@
"css-loader": "^2.1.0", "css-loader": "^2.1.0",
"electron-nucleus": "^1.11.0", "electron-nucleus": "^1.11.0",
"electron-telemetry": "git+https://github.com/thomasnordquist/electron-telemetry.git", "electron-telemetry": "git+https://github.com/thomasnordquist/electron-telemetry.git",
"number-abbreviate": "^2.0.0",
"react": "^16.8.0-alpha.1", "react": "^16.8.0-alpha.1",
"react-dom": "^16.7.0", "react-dom": "^16.7.0",
"react-redux": "^6.0.0", "react-redux": "^6.0.0",

View File

@@ -0,0 +1,131 @@
import * as React from 'react'
import * as q from '../../../backend/src/Model'
import { AppState } from '../reducers'
import { Typography } from '@material-ui/core'
import { StyleRulesCallback, withStyles } from '@material-ui/core/styles'
import { connect } from 'react-redux'
const abbreviate = require('number-abbreviate')
interface Stats {
topic: string
title: string
}
const styles: StyleRulesCallback = theme => ({
flex: {
display: 'flex',
width: '100%',
},
container: {
width: '100%',
height: '224px',
backgroundColor: 'rebeccapurple',
marginBottom: 0,
marginTop: 'auto',
padding: '8px',
},
})
interface Props {
classes: any
tree?: q.Tree
}
class BrokerStatistics extends React.Component<Props, {}> {
constructor(props: any) {
super(props)
this.state = {}
}
public render() {
const { tree, classes } = this.props
if (!tree) {
return null
}
const stats: any = {
broker: {
topic: '$SYS/broker/version',
title: 'Broker',
},
clients: {
topic: '$SYS/broker/clients/total',
title: 'Clients',
},
subscriptions: {
topic: '$SYS/broker/subscriptions/count',
title: 'Subscriptions',
},
received: {
topic: '$SYS/broker/messages/received',
title: 'Received',
},
sent: {
topic: '$SYS/broker/messages/sent',
title: 'Sent',
},
received5m: {
topic: '$SYS/broker/load/messages/received/5min',
title: 'Received last 5min',
},
sent5m: {
topic: '$SYS/broker/load/messages/sent/5min',
title: 'Sent 5m',
},
heap: {
topic: '$SYS/broker/heap/current',
title: 'Memory',
},
heapMax: {
topic: '$SYS/broker/heap/maximum',
title: 'Memory (max)',
},
}
return (
<div className={classes.container}>
{this.renderStat(tree, stats.broker)}
{this.renderPair(tree, stats.sent, stats.received)}
{this.renderPair(tree, stats.clients, stats.subscriptions)}
{this.renderPair(tree, stats.sent5m, stats.received5m)}
{this.renderPair(tree, stats.heap, stats.heapMax)}
</div>
)
}
private renderPair(tree: q.Tree, a: Stats, b: Stats) {
return (
<div className={this.props.classes.flex}>
<div style={{ flex: 1 }}>{this.renderStat(tree, a)}</div>
<div style={{ flex: 1 }}>{this.renderStat(tree, b)}</div>
</div>
)
}
public renderStat(tree: q.Tree, stat: Stats) {
const node = tree.findNode(stat.topic)
if (!node) {
return null
}
let value = node.message && node.message.value
value = !isNaN(value) ? abbreviate(value) : value
return (
<div key={stat.title}>
<Typography><b>{stat.title}</b></Typography>
<Typography style={{ paddingLeft: '8px' }}><i>{value}</i></Typography>
</div>
)
}
}
const mapStateToProps = (state: AppState) => {
return {
tree: state.connection.tree,
}
}
export default withStyles(styles)(connect(mapStateToProps)(BrokerStatistics))

View File

@@ -16,8 +16,9 @@ import { StyleRulesCallback, withStyles } from '@material-ui/core/styles'
import ChevronRight from '@material-ui/icons/ChevronRight' import ChevronRight from '@material-ui/icons/ChevronRight'
import { bindActionCreators } from 'redux' import { bindActionCreators } from 'redux'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { settingsActions } from '../actions' import { settingsActions, treeActions } from '../actions'
import { TopicOrder } from '../reducers/Settings' import { TopicOrder } from '../reducers/Settings'
import BrokerStatistics from './BrokerStatistics'
const styles: StyleRulesCallback = theme => ({ const styles: StyleRulesCallback = theme => ({
drawer: { drawer: {
@@ -39,12 +40,12 @@ const styles: StyleRulesCallback = theme => ({
}) })
interface Props { interface Props {
actions: typeof settingsActions
autoExpandLimit: number autoExpandLimit: number
visible: boolean visible: boolean
store?: any store?: any
classes: any
topicOrder: TopicOrder topicOrder: TopicOrder
classes: any
actions: typeof settingsActions
} }
class Settings extends React.Component<Props, {}> { class Settings extends React.Component<Props, {}> {
@@ -79,6 +80,7 @@ class Settings extends React.Component<Props, {}> {
{this.renderAutoExpand()} {this.renderAutoExpand()}
{this.renderNodeOrder()} {this.renderNodeOrder()}
</div> </div>
<BrokerStatistics />
</Drawer> </Drawer>
) )
} }

View File

@@ -1,5 +1,4 @@
import * as React from 'react' import * as React from 'react'
import * as q from '../../../backend/src/Model'
import { AppBar, Button, IconButton, InputBase, Toolbar, Typography } from '@material-ui/core' import { AppBar, Button, IconButton, InputBase, Toolbar, Typography } from '@material-ui/core'
import { StyleRulesCallback, withStyles } from '@material-ui/core/styles' import { StyleRulesCallback, withStyles } from '@material-ui/core/styles'

View File

@@ -56,7 +56,6 @@ class TreeNodeTitle extends React.Component<TreeNodeProps, {}> {
private renderValue() { private renderValue() {
const style: React.CSSProperties = { const style: React.CSSProperties = {
maxWidth: '15em',
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
overflow: 'hidden', overflow: 'hidden',
textOverflow: 'ellipsis', textOverflow: 'ellipsis',

View File

@@ -148,6 +148,25 @@ export class TreeNode {
return this.cachedChildTopics return this.cachedChildTopics
} }
public findNode (path: String): TreeNode | undefined {
const topics = path.split('/')
return this.findChild(topics)
}
private findChild(edges: string[]): TreeNode | undefined {
if (edges.length === 0) {
return this
}
const nextEdge = this.edges[edges[0]]
if (!nextEdge) {
return undefined
}
return nextEdge.target.findChild(edges.slice(1))
}
private mergeEdges(node: TreeNode) { private mergeEdges(node: TreeNode) {
const edgeKeys = Object.keys(node.edges) const edgeKeys = Object.keys(node.edges)
let edgesDidUpdate = false let edgesDidUpdate = false

View File

@@ -2,7 +2,6 @@ import 'mocha'
import { EventDispatcher } from '../../../../events' import { EventDispatcher } from '../../../../events'
import { expect } from 'chai' import { expect } from 'chai'
import { doesNotReject } from 'assert'
describe('EventDispatcher', async () => { describe('EventDispatcher', async () => {
it('should dispatch', async function () { it('should dispatch', async function () {

View File

@@ -1,5 +1,4 @@
import 'mocha' import 'mocha'
import './TreeNode.findNode'
import { Tree, TreeNodeFactory } from '../' import { Tree, TreeNodeFactory } from '../'

View File

@@ -1,5 +1,4 @@
import 'mocha' import 'mocha'
import './TreeNode.findNode'
import { TreeNodeFactory } from '../' import { TreeNodeFactory } from '../'
import { expect } from 'chai' import { expect } from 'chai'

View File

@@ -1,19 +0,0 @@
import { TreeNode } from '../'
declare module '../' {
interface TreeNode {
findNode(path: String): TreeNode | undefined
}
}
TreeNode.prototype.findNode = function (path: String): TreeNode | undefined {
const topics = path.split('/')
const edge = this.edges[topics[0]]
const remainingTopics = topics.slice(1, topics.length)
if (edge && remainingTopics.length === 0) {
return edge.target
} else if (edge) {
return edge.target.findNode(remainingTopics.join('/'))
}
return undefined
}

View File

@@ -1,4 +1,3 @@
import './TreeNode.findNode'
import 'mocha' import 'mocha'
import { TreeNodeFactory } from '../' import { TreeNodeFactory } from '../'

View File

@@ -1,5 +1,4 @@
import 'mocha' import 'mocha'
import './TreeNode.findNode'
import { TreeNodeFactory } from '../' import { TreeNodeFactory } from '../'
import { expect } from 'chai' import { expect } from 'chai'