From 875ca384a0b926ddc0be8c2ebf717ab4f6ab0ae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81rgio=20Ramos?= Date: Fri, 11 Nov 2016 17:56:42 +0000 Subject: [PATCH] stacking graphs --- spikes/graphs-fe/chartjs/server/metric.js | 2 +- .../graphs-matrix/chartjs/client/actions.js | 26 +++- spikes/graphs-matrix/chartjs/client/chart.js | 144 ------------------ .../chartjs/client/chart/base.js | 71 +++++++++ .../graphs-matrix/chartjs/client/chart/cpu.js | 31 ++++ .../chartjs/client/chart/disk.js | 35 +++++ .../chartjs/client/chart/index.js | 8 + .../graphs-matrix/chartjs/client/chart/mem.js | 28 ++++ spikes/graphs-matrix/chartjs/client/index.js | 2 - spikes/graphs-matrix/chartjs/client/matrix.js | 63 +++----- spikes/graphs-matrix/chartjs/client/root.js | 2 +- spikes/graphs-matrix/chartjs/package.json | 6 + spikes/graphs-matrix/chartjs/server/metric.js | 45 +++++- .../graphs-matrix/chartjs/static/index.html | 10 -- 14 files changed, 266 insertions(+), 207 deletions(-) delete mode 100644 spikes/graphs-matrix/chartjs/client/chart.js create mode 100644 spikes/graphs-matrix/chartjs/client/chart/base.js create mode 100644 spikes/graphs-matrix/chartjs/client/chart/cpu.js create mode 100644 spikes/graphs-matrix/chartjs/client/chart/disk.js create mode 100644 spikes/graphs-matrix/chartjs/client/chart/index.js create mode 100644 spikes/graphs-matrix/chartjs/client/chart/mem.js diff --git a/spikes/graphs-fe/chartjs/server/metric.js b/spikes/graphs-fe/chartjs/server/metric.js index 0d64fad2..b7031178 100644 --- a/spikes/graphs-fe/chartjs/server/metric.js +++ b/spikes/graphs-fe/chartjs/server/metric.js @@ -19,7 +19,7 @@ module.exports = (server) => ({ when: new Date().getTime(), cpu: Math.random() * 100 }); - }, 400); + }, 45); cdm[id] = { interval, diff --git a/spikes/graphs-matrix/chartjs/client/actions.js b/spikes/graphs-matrix/chartjs/client/actions.js index d48d610c..852bf7ea 100644 --- a/spikes/graphs-matrix/chartjs/client/actions.js +++ b/spikes/graphs-matrix/chartjs/client/actions.js @@ -2,11 +2,29 @@ const take = require('lodash.take'); const actions = { 'UPDATE_STATS': (state, action) => { - const data = [action.payload].concat(state[action.subscription] || []); + const data = (state[action.subscription] || { + cpu: [], + mem: [], + disk: [] + }); + + const newData = ['cpu', 'mem', 'disk'].reduce((sum, key) => { + const item = { + ...action.payload.stats[key], + when: action.payload.when + }; + + const prepended = [item].concat(data[key]); + + return { + ...sum, + [key]: take(prepended, state.windowSize) + }; + }, {}); return { ...state, - [action.subscription]: take(data, state.windowSize) + [action.subscription]: newData }; } }; @@ -37,7 +55,7 @@ module.exports.subscribe = (id) => (dispatch, getState) => { }); return dispatch({ - action: 'SUBSCRIBE', + type: 'SUBSCRIBE', payload: p }); }; @@ -58,7 +76,7 @@ module.exports.unsubscribe = (id) => (dispatch, getState) => { }); return dispatch({ - action: 'UNSUBSCRIBE', + type: 'UNSUBSCRIBE', payload: p }); }; \ No newline at end of file diff --git a/spikes/graphs-matrix/chartjs/client/chart.js b/spikes/graphs-matrix/chartjs/client/chart.js deleted file mode 100644 index cae1536f..00000000 --- a/spikes/graphs-matrix/chartjs/client/chart.js +++ /dev/null @@ -1,144 +0,0 @@ -const buildArray = require('build-array'); -const Chart = require('chart.js'); -const React = require('react'); - -// borderSkipped -// patch `.draw` to support `borderSkipped`: -// Chart.elements.Rectangle.prototype.draw = function() { -// var ctx = this._chart.ctx; -// var vm = this._view; -// -// var halfWidth = vm.width / 2, -// leftX = vm.x - halfWidth, -// rightX = vm.x + halfWidth, -// top = vm.base - (vm.base - vm.y), -// halfStroke = vm.borderWidth / 2; -// -// // Canvas doesn't allow us to stroke inside the width so we can -// // adjust the sizes to fit if we're setting a stroke on the line -// if (vm.borderWidth) { -// leftX += halfStroke; -// rightX -= halfStroke; -// top += halfStroke; -// } -// -// ctx.beginPath(); -// ctx.fillStyle = vm.backgroundColor; -// ctx.strokeStyle = vm.borderColor; -// ctx.lineWidth = vm.borderWidth; -// -// var borderSkipped = !Array.isArray(vm.borderSkipped) -// ? [vm.borderSkipped] -// : vm.borderSkipped; -// -// // Corner points, from bottom-left to bottom-right clockwise -// // | 1 2 | -// // | 0 3 | -// var corners = [ -// [leftX, vm.base, (borderSkipped.indexOf('bottom') >= 0), 'bottom'], -// [leftX, top, (borderSkipped.indexOf('left') >= 0), 'left'], -// [rightX, top, (borderSkipped.indexOf('top') >= 0), 'top'], -// [rightX, vm.base, (borderSkipped.indexOf('right') >= 0), 'right'] -// ]; -// -// function cornerAt(index) { -// return corners[index % 4]; -// } -// -// // Draw rectangle from 'startCorner' -// var corner = cornerAt(0); -// ctx.moveTo(corner[0], corner[1]); -// -// for (var i = 1; i < 5; i++) { -// corner = cornerAt(i); -// ctx.lineTo(corner[0], corner[1]); -// -// if (!corner[2]) { -// ctx.stroke(); -// } -// } -// -// console.log(corners); -// -// ctx.fill(); -// }; - -module.exports = React.createClass({ - ref: function(name) { - this._refs = this._refs || {}; - - return (el) => { - this._refs[name] = el; - }; - }, - fromData: function(data) { - return (data || []).map((d) => { - return d.cpu; - }); - }, - componentDidMount: function() { - const { - data = [], - bg, - border - } = this.props; - - const bars = this.fromData(data); - - this._chart = new Chart(this._refs.component, { - type: 'bar', - options: { - elements: { - rectangle: { - borderSkipped: ['bottom', 'left', 'right'] - } - }, - scales: { - xAxes: [{ - display: false - }], - yAxes: [{ - display: false - }] - }, - legend: { - display: false - } - }, - data: { - labels: buildArray(bars.length).map((v, i) => ''), - datasets: [{ - borderWidth: 1, - borderColor: border, - backgroundColor: bg, - data: bars - }] - } - }); - }, - componentWillReceiveProps: function(nextProps) { - const { - data = [], - bg, - border - } = this.props; - - const bars = this.fromData(data); - - this._chart.data.labels = buildArray(bars.length).map((v, i) => ''); - this._chart.data.datasets[0].backgroundColor = bg; - this._chart.data.datasets[0].borderColor = border; - this._chart.data.datasets[0].data = bars; - - this._chart.update(0); - }, - render: function() { - return ( - - ); - } -}); diff --git a/spikes/graphs-matrix/chartjs/client/chart/base.js b/spikes/graphs-matrix/chartjs/client/chart/base.js new file mode 100644 index 00000000..d3c52441 --- /dev/null +++ b/spikes/graphs-matrix/chartjs/client/chart/base.js @@ -0,0 +1,71 @@ +const buildArray = require('build-array'); +const Chart = require('chart.js'); +const React = require('react'); + +module.exports = React.createClass({ + ref: function(name) { + this._refs = this._refs || {}; + + return (el) => { + this._refs[name] = el; + }; + }, + componentDidMount: function() { + const { + datasets = [], + labels = 0, + stacked = false, + xAxe = false, + yAxe = false, + legend = false + } = this.props; + + const _labels = !Array.isArray(labels) + ? buildArray(labels).map((v, i) => '') + : labels; + + this._chart = new Chart(this._refs.component, { + type: 'bar', + stacked: stacked, + responsive: true, + options: { + scales: { + xAxes: [{ + display: xAxe, + stacked: stacked + }], + yAxes: [{ + display: yAxe, + stacked: stacked + }] + }, + legend: { + display: legend + } + }, + data: { + labels: + datasets: datasets + } + }); + }, + componentWillReceiveProps: function(nextProps) { + const { + datasets = [], + labels = 0 + } = this.props; + + this._chart.data.datasets = datasets; + this._chart.data.labels = buildArray(labels).map((v, i) => ''); + this._chart.update(0); + }, + render: function() { + return ( + + ); + } +}); diff --git a/spikes/graphs-matrix/chartjs/client/chart/cpu.js b/spikes/graphs-matrix/chartjs/client/chart/cpu.js new file mode 100644 index 00000000..6df20000 --- /dev/null +++ b/spikes/graphs-matrix/chartjs/client/chart/cpu.js @@ -0,0 +1,31 @@ +const buildArray = require('build-array'); +const Chart = require('./base'); +const React = require('react'); + +const colors = { + user: 'rgb(255, 99, 132)', + sys: 'rgb(255, 159, 64)' +}; + +module.exports = ({ + data = {}, + windowSize +}) => { + const datasets = ['user', 'sys'].map((key) => { + return { + label: key, + backgroundColor: colors[key], + data: buildArray(windowSize).map((v, i) => ((data[i] || {})[key] || 0)) + }; + }); + + return ( + + ); +}; + diff --git a/spikes/graphs-matrix/chartjs/client/chart/disk.js b/spikes/graphs-matrix/chartjs/client/chart/disk.js new file mode 100644 index 00000000..64e0221c --- /dev/null +++ b/spikes/graphs-matrix/chartjs/client/chart/disk.js @@ -0,0 +1,35 @@ +const pretty = require('prettysize'); +const buildArray = require('build-array'); +const Chart = require('./base'); +const React = require('react'); + +const colors = { + user: 'rgb(255, 99, 132)', + sys: 'rgb(255, 159, 64)' +}; + +module.exports = ({ + data = [], + windowSize +}) => { + const datasets = [{ + label: 'disk', + backgroundColor: 'rgb(255, 159, 64)', + data: buildArray(windowSize).map((v, i) => { + return data[i] ? (data[i].total - data[i].free) : 0; + }) + }]; + + const labels = buildArray(windowSize).map((v, i) => { + return data[i] ? pretty(datasets[0].data[i]) : ''; + }); + + return ( + + ); +}; + diff --git a/spikes/graphs-matrix/chartjs/client/chart/index.js b/spikes/graphs-matrix/chartjs/client/chart/index.js new file mode 100644 index 00000000..43dc4817 --- /dev/null +++ b/spikes/graphs-matrix/chartjs/client/chart/index.js @@ -0,0 +1,8 @@ +module.exports = { + CPU: require('./cpu'), + cpu: require('./cpu'), + Mem: require('./mem'), + mem: require('./mem'), + Disk: require('./disk'), + disk: require('./disk') +}; diff --git a/spikes/graphs-matrix/chartjs/client/chart/mem.js b/spikes/graphs-matrix/chartjs/client/chart/mem.js new file mode 100644 index 00000000..a9a0943d --- /dev/null +++ b/spikes/graphs-matrix/chartjs/client/chart/mem.js @@ -0,0 +1,28 @@ +const buildArray = require('build-array'); +const Chart = require('./base'); +const React = require('react'); + +const colors = { + user: 'rgb(255, 99, 132)', + sys: 'rgb(255, 159, 64)' +}; + +module.exports = ({ + data = [], + windowSize +}) => { + const datasets = [{ + label: 'mem', + backgroundColor: 'rgb(255, 99, 132)', + data: buildArray(windowSize).map((v, i) => ((data[i] || {}).used || 0)) + }]; + + return ( + + ); +}; + diff --git a/spikes/graphs-matrix/chartjs/client/index.js b/spikes/graphs-matrix/chartjs/client/index.js index cc89c799..fea081b5 100644 --- a/spikes/graphs-matrix/chartjs/client/index.js +++ b/spikes/graphs-matrix/chartjs/client/index.js @@ -13,8 +13,6 @@ client.connect((err) => { if (err) { throw err; } - - console.log('connected'); }); const store = Store({ diff --git a/spikes/graphs-matrix/chartjs/client/matrix.js b/spikes/graphs-matrix/chartjs/client/matrix.js index af1eb755..3c520efb 100644 --- a/spikes/graphs-matrix/chartjs/client/matrix.js +++ b/spikes/graphs-matrix/chartjs/client/matrix.js @@ -31,7 +31,7 @@ const mapDispatchToProps = (dispatch, ownProps) => { } }; -const Graph = connect( +const Row = connect( mapStateToProps, mapDispatchToProps, )(React.createClass({ @@ -43,62 +43,47 @@ const Graph = connect( }, render: function() { const { - data = [], + data = {}, windowSize } = this.props; - const _data = buildArray(windowSize).map((v, i) => { - return data[i] ? data[i] : { - cpu: 0, - when: new Date().getTime() - }; - }); + const charts = Object.keys(data).map((key, i, arr) => { + if (!Chart[key]) { + return null; + } - const median = data.reduce((sum, v) => (sum + v.cpu), 0) / data.length; + const chart = React.createElement(Chart[key], { + data: data[key], + windowSize + }); - const bg = median > 50 - ? 'rgba(205, 54, 54, 0.3)' - : 'rgba(54, 74, 205, 0.3)'; - - const border = median > 50 - ? 'rgba(248, 51, 51, 0.5)' - : 'rgba(54, 73, 205, 0.5)'; - - return ( - - ); - } -})); - -module.exports = ({ - x, - y -}) => { - const m = buildArray(y).map((v, i) => { - const m = buildArray(x).map((v, y) => { - const id = `${i}${y}`; return ( -
- +
+ {chart}
); }); return (
- {m} + {charts}
); + } +})); + +module.exports = ({ + rows +}) => { + const _rows = buildArray(rows).map((v, i) => { + return ( + + ); }); return (
- {m} + {_rows}
); }; diff --git a/spikes/graphs-matrix/chartjs/client/root.js b/spikes/graphs-matrix/chartjs/client/root.js index 58534619..cb128946 100644 --- a/spikes/graphs-matrix/chartjs/client/root.js +++ b/spikes/graphs-matrix/chartjs/client/root.js @@ -17,7 +17,7 @@ module.exports = ({ return ( - + ); diff --git a/spikes/graphs-matrix/chartjs/package.json b/spikes/graphs-matrix/chartjs/package.json index 65122fd3..6659ed98 100644 --- a/spikes/graphs-matrix/chartjs/package.json +++ b/spikes/graphs-matrix/chartjs/package.json @@ -4,6 +4,7 @@ "license": "private", "main": "server/index.js", "dependencies": { + "async": "^2.1.2", "autoprefixer": "^6.5.1", "babel-eslint": "^7.0.0", "babel-loader": "^6.2.5", @@ -19,16 +20,21 @@ "chart.js": "^2.3.0", "classnames": "^2.2.5", "component-emitter": "^1.2.1", + "cpu-percent": "^2.0.1", "css-loader": "^0.25.0", "d3": "^4.3.0", + "diskusage": "^0.1.5", "hapi": "^15.2.0", "hapi-webpack-dev-plugin": "^1.1.4", "inert": "^4.0.2", "lodash.take": "^4.1.1", + "metrics-os": "^1.0.1", "nes": "^6.3.1", + "pidusage": "^1.1.0", "postcss-loader": "^1.0.0", "postcss-modules-values": "^1.2.2", "postcss-nested": "^1.0.0", + "prettysize": "0.0.3", "react": "^15.3.2", "react-dom": "^15.3.2", "react-hot-loader": "^3.0.0-beta.6", diff --git a/spikes/graphs-matrix/chartjs/server/metric.js b/spikes/graphs-matrix/chartjs/server/metric.js index 24015f70..8067be3a 100644 --- a/spikes/graphs-matrix/chartjs/server/metric.js +++ b/spikes/graphs-matrix/chartjs/server/metric.js @@ -1,7 +1,39 @@ -const Emitter = require('component-emitter'); +const async = require('async'); +const disk = require('diskusage'); +const os = require('os'); const cdm = {}; +const getCPU = (fn) => { + return fn(null, { + user: os.cpus().reduce((sum, cpu) => sum + cpu.times.user, 0), + sys: os.cpus().reduce((sum, cpu) => sum + cpu.times.sys, 0) + }); +}; + +const getMem = (fn) => { + const free = os.freemem(); + const total = os.totalmem(); + const using = total - free; + const perc = (using / total) * 100; + + return fn(null, { + used: perc + }); +}; + +const getDisk = (fn) => { + disk.check('/', fn); +}; + +const getStats = (fn) => { + async.parallel({ + cpu: getCPU, + mem: getMem, + disk: getDisk + }, fn); +}; + module.exports = (server) => ({ on: (id) => { console.log('on', cdm[id]); @@ -10,16 +42,17 @@ module.exports = (server) => ({ return; } - let messageId = 0; const interval = setInterval(() => { console.log(`publishing /stats/${id}`); - server.publish(`/stats/${id}`, { - when: new Date().getTime(), - cpu: Math.random() * 100 + getStats((err, stats) => { + server.publish(`/stats/${id}`, { + when: new Date().getTime(), + stats + }); }); - }, 100); + }, 1000); cdm[id] = { interval, diff --git a/spikes/graphs-matrix/chartjs/static/index.html b/spikes/graphs-matrix/chartjs/static/index.html index fd29e69d..c012e3d4 100644 --- a/spikes/graphs-matrix/chartjs/static/index.html +++ b/spikes/graphs-matrix/chartjs/static/index.html @@ -3,16 +3,6 @@ React Boilerplate - -