Adds a network traffic widget

This commit is contained in:
Alicia Sykes 2022-01-18 23:07:24 +00:00
parent 6d9e34c90f
commit 88727cf2e2
3 changed files with 146 additions and 5 deletions

View File

@ -53,6 +53,7 @@ Dashy has support for displaying dynamic content in the form of widgets. There a
- [System Load](#system-load)
- [System Load History](#system-load-history)
- [Network Interfaces](#network-interfaces)
- [Network Traffic](#network-traffic)
- [Resource Usage Alerts](#resource-usage-alerts)
- **[Dynamic Widgets](#dynamic-widgets)**
- [Iframe Widget](#iframe-widget)
@ -1185,7 +1186,7 @@ All Glance's based widgets require a `hostname`
**Field** | **Type** | **Required** | **Description**
--- | --- | --- | ---
**`hostname`** | `string` | Required | The URL to your Glances instance, without a trailing slash
**`hostname`** | `string` | Required | The URL to your Glances instance (without a trailing slash)
##### Info
@ -1372,6 +1373,23 @@ Lists visible network interfaces, including real-time upload/ download stats
---
### Network Traffic
Shows amount of data recently uploaded/ downloaded across all network interfaces. Optionally set the `limit` option to specify number historical of data points to return
<p align="center"><img width="400" src="https://i.ibb.co/12RN6KT/gl-network-traffic.png" /></p>
##### Example
```yaml
- type: gl-network-traffic
options:
hostname: http://192.168.130.2:61208
limit: 500
```
---
### Resource Usage Alerts
Lists recent high resource usage alerts (e.g. CPU, mem, IO, load, temp)
@ -1577,7 +1595,9 @@ For more info on how to apply custom variables, see the [Theming Docs](/docs/the
### Customizing Charts
For widgets that contain charts, you can set an array of colors under `chartColors`. To specify the chart height, set `chartHeight` to an integer (in `px`), defaults to `300`. For example:
For widgets that contain charts, you can set an array of colors under `chartColors`.
To specify the chart height, set `chartHeight` to an integer (in `px`), defaults to `300`.
For example:
```yaml
- type: gl-load-history
@ -1601,13 +1621,13 @@ For more info about multi-language support, see the [Internationalization Docs](
### Widget UI Options
Widgets can be opened in full-page view, by clicking the Arrow icon (top-right). The URL in your address bar will also update, and visiting that web address will take you straight to the selected widget.
Widgets can be opened in full-page view, by clicking the Arrow icon (top-right). The URL in your address bar will also update, and visiting that web address directly will take you straight to that widget.
You can reload the data of any widget, by clicking the Refresh Data icon (also in top-right). This will only affect the widget where the action was triggered from.
All [config options](/docs/configuring.md#section) that can be applied to sections, can also be applied to widget sections. For example, to make a widget span multiple columns, set `displayData.cols: 2` within the parent section. You can collapse a widget (by clicking the section title), and collapse state will be saved locally.
All [config options](/docs/configuring.md#section) that can be applied to sections, can also be applied to widget sections. For example, to make a widget section double the width, set `displayData.cols: 2` within the parent section. You can collapse a widget (by clicking the section title), and collapse state will be saved locally.
Widgets cannot currently be edited through the UI. This feature is in development, and will be released soon. In the meantime, you can either use the JSON config editor, or use VS Code or SSH into your box to edit the conf.yml file directly.
Widgets cannot currently be edited through the UI. This feature is in development, and will be released soon. In the meantime, you can either use the JSON config editor, or use [VS Code Server](https://github.com/coder/code-server), or just SSH into your box and edit the conf.yml file directly.
---

View File

@ -0,0 +1,113 @@
<template>
<div class="glances-cpu-history-wrapper">
<div class="gl-history-chart" :id="chartId"></div>
</div>
</template>
<script>
import WidgetMixin from '@/mixins/WidgetMixin';
import ChartingMixin from '@/mixins/ChartingMixin';
import { convertBytes, getTimeAgo, timestampToTime } from '@/utils/MiscHelpers';
export default {
mixins: [WidgetMixin, ChartingMixin],
components: {},
data() {
return {};
},
computed: {
hostname() {
if (!this.options.hostname) this.error('You must specify a \'hostname\' for Glaces');
return this.options.hostname;
},
limit() {
return this.options.limit || 100;
},
endpoint() {
return `${this.hostname}/api/3/network/history/${this.limit}`;
},
},
methods: {
fetchData() {
this.makeRequest(this.endpoint).then(this.processData);
},
processData(trafficData) {
const preliminary = {
upload: [],
download: [],
};
/* eslint-disable prefer-destructuring */
Object.keys(trafficData).forEach((keyName) => {
let upOrDown = null;
if (keyName.includes('_tx')) upOrDown = 'up';
else if (keyName.includes('_rx')) upOrDown = 'down';
trafficData[keyName].forEach((dataPoint) => {
const dataTime = this.getRoundedTime(dataPoint[0]);
if (upOrDown === 'up') {
if (preliminary.upload[dataTime]) preliminary.upload[dataTime] += dataPoint[1];
else preliminary.upload[dataTime] = dataPoint[1];
} else if (upOrDown === 'down') {
if (preliminary.download[dataTime]) preliminary.download[dataTime] += dataPoint[1];
else preliminary.download[dataTime] = dataPoint[1];
}
});
});
const timeLabels = [];
const uploadData = [];
const downloadData = [];
const startDate = Object.keys(preliminary.upload)[0];
Object.keys(preliminary.upload).forEach((date) => {
timeLabels.push(timestampToTime(date));
uploadData.push(preliminary.upload[date]);
});
Object.keys(preliminary.download).forEach((date) => {
downloadData.push(preliminary.download[date]);
});
const datasets = [
{ name: 'Upload', type: 'bar', values: uploadData },
{ name: 'Download', type: 'bar', values: downloadData },
];
const chartTitle = this.makeTitle(startDate);
this.generateChart({ labels: timeLabels, datasets }, chartTitle);
},
getRoundedTime(date) {
const roundTo = 1000 * 60;
return new Date(Math.round(new Date(date).getTime() / roundTo) * roundTo);
},
makeTitle(startDate) {
return `Network Activity over past ${getTimeAgo(startDate).replace('ago', '')}`;
},
generateChart(timeChartData, chartTitle) {
return new this.Chart(`#${this.chartId}`, {
title: chartTitle,
data: timeChartData,
type: 'axis-mixed',
height: this.chartHeight,
colors: ['#f6f000', '#04e4f4'],
truncateLegends: true,
lineOptions: {
regionFill: 1,
hideDots: 1,
},
axisOptions: {
xIsSeries: true,
xAxisMode: 'tick',
},
tooltipOptions: {
formatTooltipY: d => convertBytes(d),
},
});
},
},
created() {
this.overrideUpdateInterval = 10;
},
};
</script>
<style scoped lang="scss">
.glances-cpu-history-wrapper {
.gl-history-chart {}
}
</style>

View File

@ -179,6 +179,13 @@
@error="handleError"
:ref="widgetRef"
/>
<GlNetworkTraffic
v-else-if="widgetType === 'gl-network-activity'"
:options="widgetOptions"
@loading="setLoaderState"
@error="handleError"
:ref="widgetRef"
/>
<GlSystemLoad
v-else-if="widgetType === 'gl-system-load'"
:options="widgetOptions"
@ -386,6 +393,7 @@ export default {
GlMemGauge: () => import('@/components/Widgets/GlMemGauge.vue'),
GlMemHistory: () => import('@/components/Widgets/GlMemHistory.vue'),
GlNetworkInterfaces: () => import('@/components/Widgets/GlNetworkInterfaces.vue'),
GlNetworkTraffic: () => import('@/components/Widgets/GlNetworkTraffic.vue'),
GlSystemLoad: () => import('@/components/Widgets/GlSystemLoad.vue'),
HealthChecks: () => import('@/components/Widgets/HealthChecks.vue'),
IframeWidget: () => import('@/components/Widgets/IframeWidget.vue'),