summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUdo Walter2019-01-22 22:16:32 +0100
committerUdo Walter2019-01-22 22:16:32 +0100
commit724efa2e57565a78a76a7a341927af54e2bd237c (patch)
treece6133df9829ddf08c7496da4d01ea0bdf7a5529
parentrework new_status-dnbd3.html with vuejs instead of jquery (diff)
downloaddnbd3-status-724efa2e57565a78a76a7a341927af54e2bd237c.tar.gz
dnbd3-status-724efa2e57565a78a76a7a341927af54e2bd237c.tar.xz
dnbd3-status-724efa2e57565a78a76a7a341927af54e2bd237c.zip
Add server speeds graph, option to show peak speeds and some design changes
Options/query strings: 'peak' to turn on peak speed instead of average speed 'timespan' the timespan in which to calculate the average and peak speeds (default: 120) (seconds)
-rw-r--r--static/new_status-dnbd3.html170
1 files changed, 131 insertions, 39 deletions
diff --git a/static/new_status-dnbd3.html b/static/new_status-dnbd3.html
index b4049bb..cb26cba 100644
--- a/static/new_status-dnbd3.html
+++ b/static/new_status-dnbd3.html
@@ -4,16 +4,32 @@
<head>
<style type="text/css">
- body { margin: 0; }
+ html, body {
+ height: 100%;
+ margin: 0;
+ }
+
+ #app {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ }
- .container {
+ .server-container {
display: flex;
+ justify-content: center;
+ overflow-y: auto;
}
.server {
border-spacing: 5px;
background-color: #eee;
border: 1px solid #666;
+ flex: 1;
+ white-space: nowrap;
+ max-width: 360px;
+ margin: 5px;
}
.first-row {
@@ -28,9 +44,9 @@
border: 1px solid black;
text-align: center;
}
-
- .client-speed {
- width: 240px;
+
+ .expand {
+ width: 99%;
}
</style>
@@ -38,67 +54,112 @@
<body>
<div id="app">
- <div class="container">
- <table v-for="server in servers" class="server">
+ <div class="server-container">
+ <table v-for="(server, index) in servers" class="server" :style="{ border: '2px solid ' + GRAPH_COLORS[index] }">
<tbody>
- <tr class="first-row"><td>Server IP:</td><td class="server-ip">{{ server.address }}</td></tr>
- <tr><td>Uptime:</td><td>{{ formatSeconds(server.uptime) }}</td></tr>
- <tr><td>Upload speed:</td><td>{{ formatBytes(server.uploadSpeed) +'/s' }}</td></tr>
- <tr><td>Download speed:</td><td>{{ formatBytes(server.downloadSpeed) +'/s' }}</td></tr>
+ <tr class="first-row"><td colspan="2" class="server-ip">{{ server.address }}</td></tr>
+ <tr><td>Uptime:</td><td class="expand">{{ formatSeconds(server.uptime) }}</td></tr>
+ <tr><td>Upload speed:</td><td>{{ formatBytes(peak ? server.peakUploadSpeed : server.avgUploadSpeed) +'/s' }}</td></tr>
+ <tr><td>Download speed:</td><td>{{ formatBytes(peak ? server.peakDownloadSpeed : server.avgDownloadSpeed) +'/s' }}</td></tr>
<tr><td>Total sent:</td><td>{{ formatBytes(server.bytesSent) }}</td></tr>
<tr><td>Total received:</td><td>{{ formatBytes(server.bytesReceived) }}</td></tr>
+ <tr><td>Client count:</td><td>{{ server.clientCount }}</td></tr>
<tr v-for="client in server.clients">
<td class="client-label">{{ client.address.split( ":" )[0] }}</td>
- <td class="client-speed" :style="calcBackgroundStyle(client.uploadSpeed)"><span>{{ formatBytes(client.uploadSpeed) + '/s' }}</span></td>
+ <td class="client-speed" :style="calcBackgroundStyle(peak ? client.peakUploadSpeed : client.avgUploadSpeed)">
+ <span>{{ formatBytes(peak ? client.peakUploadSpeed : client.avgUploadSpeed) + '/s' }}</span>
+ </td>
</tr>
</tbody>
</table>
</div>
+ <canvas ref="chart" :width="this.canvasWidth"></canvas>
</div>
<script src="vue.min.js"></script>
+<script src="smoothie.js"></script>
+
<script>
var app = new Vue({
el: '#app',
data: {
- data: {},
- log: { server: {}, client: {} },
- timespan: 120
+ rawData: {},
+ servers: [],
+ logs: {},
+ timespan: 120,
+ peak: false,
+ canvasWidth: 0,
+ smoothie: null,
+ graphLines: {},
+ GRAPH_COLORS: ["#3366cc", "#dc3912", "#ff9900", "#109618", "#990099", "#0099c6", "#dd4477", "#66aa00", "#b82e2e", "#316395", "#994499", "#22aa99", "#aaaa11", "#6633cc", "#e67300", "#8b0707", "#651067", "#329262", "#5574a6", "#3b3eac"]
},
- computed: {
- servers () {
- if (!this.data.servers) return []
- const servers = this.data.servers.slice(0)
- servers.sort((a, b) => b.clients.length - a.clients.length)
- servers.forEach(server => {
- this.calcSpeed('server', server)
- server.clients.forEach(client => {
- this.calcSpeed('client', client, server.timestamp)
+ watch: {
+ rawData () {
+ if (this.rawData.servers) {
+ const servers = this.rawData.servers.slice(0)
+ servers.sort(this.compareObjectIps)
+ const currentTime = new Date().getTime()
+ servers.forEach((server, index) => {
+ this.calcSpeed(server)
+
+ // Update the graph
+ if (!this.graphLines[server.address]) {
+ Vue.set(this.graphLines, server.address, new TimeSeries({ logarithmicScale: true }))
+ this.smoothie.addTimeSeries(this.graphLines[server.address], { lineWidth: 2, strokeStyle: this.GRAPH_COLORS[index] })
+ }
+ this.graphLines[server.address].append(currentTime, server.uploadSpeed)
+
+ // Update clients
+ server.clients.forEach(client => {
+ client.timestamp = server.timestamp
+ this.calcSpeed(client)
+ })
+ if (this.peak) {
+ server.clients = server.clients.filter(client => client.peakUploadSpeed > 0)
+ server.clients.sort((a, b) => b.peakUploadSpeed - a.peakUploadSpeed)
+ } else {
+ server.clients = server.clients.filter(client => client.avgUploadSpeed > 0)
+ server.clients.sort((a, b) => b.avgUploadSpeed - a.avgUploadSpeed)
+ }
})
- server.clients = server.clients.filter(client => client.uploadSpeed > 0)
- server.clients.sort((a, b) => b.uploadSpeed - a.uploadSpeed)
- })
- return servers
+ this.servers = servers
+ }
}
},
methods: {
async updateData () {
const response = await fetch('/data2.json')
- this.data = await response.json()
+ this.rawData = await response.json()
setTimeout(this.updateData, 2000)
},
- calcSpeed (type, obj, timestamp) {
- var log = this.log[type][obj.address]
- log = this.log[type][obj.address] = log ? log.filter(x => x.timestamp > this.data.timestamp - this.timespan * 1000) : []
- if (timestamp) obj.timestamp = timestamp
- log.push(obj)
- if (log.length > 0) {
- const a = log[0]
+ calcSpeed (obj) {
+ // Create a log for this ip if it doesn't exist already
+ if(!this.logs[obj.address]) Vue.set(this.logs, obj.address, [])
+ // Remove outdated values
+ this.logs[obj.address] = this.logs[obj.address].filter(x => x.timestamp > this.rawData.timestamp - this.timespan * 1000)
+ // Get the all the old values accumulated over the timespan
+ const log = this.logs[obj.address]
+ // Add new values to the log
+ if (log.length === 0 || obj.timestamp > log[log.length - 1].timestamp) log.push(obj)
+
+ if (log.length > 1) {
+ // Calculate current speeds
+ var a = log[log.length - 2]
const b = log[log.length - 1]
- const time = (b.timestamp - a.timestamp) / 1000
+ var time = (b.timestamp - a.timestamp) / 1000
obj.uploadSpeed = (b.bytesSent - a.bytesSent) / time
- if (type === 'server') obj.downloadSpeed = (b.bytesReceived - a.bytesReceived) / time
+ obj.downloadSpeed = (b.bytesReceived - a.bytesReceived) / time
+
+ // Calculate peak speeds
+ obj.peakUploadSpeed = Math.max(...log.map(x => x.uploadSpeed || 0))
+ obj.peakDownloadSpeed = Math.max(...log.map(x => x.downloadSpeed || 0))
+
+ // Calculate average speeds
+ a = log[0]
+ time = (b.timestamp - a.timestamp) / 1000
+ obj.avgUploadSpeed = (b.bytesSent - a.bytesSent) / time
+ obj.avgDownloadSpeed = (b.bytesReceived - a.bytesReceived) / time
}
},
formatBytes (bytes) {
@@ -114,18 +175,49 @@ var app = new Vue({
+ Math.floor(seconds / 60 ) % 60 + 'min' )
},
calcBackgroundStyle (speed) {
- const percent = Math.round(Math.max(0, Math.min(100, Math.log(1 + speed * (100000 / 1073741824)) / Math.log(100000) * 100)))
+ const percent = Math.round(Math.max(0, Math.min(100, this.logScale(speed) / this.logScale(262144000) * 100)))
var color = '#056d00'
if (speed < 1048576) color = '#8adb8b'
else if (speed < 10485760) color = '#5cdb55'
else if (speed < 104857600) color = '#26a81f'
return { background: `linear-gradient(90deg, ${color} ${percent}%, #e0e0e0 ${percent}%)` }
+ },
+ compareObjectIps (obj1, obj2) {
+ const parts1 = obj1.address.split('.').map(str => parseInt(str))
+ const parts2 = obj2.address.split('.').map(str => parseInt(str))
+ var result = parts1[0] - parts2[0]
+ if (result === 0) result = parts1[1] - parts2[1]
+ if (result === 0) result = parts1[2] - parts2[2]
+ if (result === 0) result = parts1[3] - parts2[3]
+ return result
+ },
+ logScale (value) {
+ return Math.log(value/100000 + 1)
}
},
created () {
const urlParams = new URLSearchParams(window.location.search)
this.timespan = parseInt(urlParams.get('timespan')) || 120
+ this.peak = urlParams.get('peak') === 'true' || urlParams.get('peak') === ''
this.updateData()
+ },
+ mounted () {
+ this.canvasWidth = window.innerWidth
+ window.addEventListener('resize', () => {
+ this.canvasWidth = window.innerWidth
+ })
+ this.smoothie = new SmoothieChart({
+ 'millisPerPixel': 300,
+ 'grid': { 'millisPerLine': 30000 },
+ timestampFormatter: SmoothieChart.timeFormatter,
+ yMaxFormatter: this.formatBytes,
+ yMinFormatter: this.formatBytes,
+ valueTransformFunction: this.logScale,
+ minValue: 0,
+ maxValue: 262144000,
+ labels: { fontSize: 13 }
+ })
+ this.smoothie.streamTo(this.$refs.chart, 2000)
}
})