mirror of
https://github.com/OkaeriPoland/okaeri-timings.git
synced 2026-01-18 03:28:20 +01:00
Break down frontend into components, use backend-side parsing
This commit is contained in:
@@ -119,3 +119,4 @@ else
|
|||||||
|
|
||||||
echo "[$(date '+%Y/%m/%d %H:%M:%S')] Done!"
|
echo "[$(date '+%Y/%m/%d %H:%M:%S')] Done!"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<MDBContainer class="my-5">
|
<MDBContainer class="my-5">
|
||||||
<MDBRow class="gy-4">
|
<MDBRow class="gy-4">
|
||||||
|
|
||||||
<MDBCol md="12" v-if="!summaryLoaded">
|
<MDBCol md="12" v-if="!report">
|
||||||
<MDBCard>
|
<MDBCard>
|
||||||
<MDBCardBody>
|
<MDBCardBody>
|
||||||
<MDBCardTitle>1. Generate report</MDBCardTitle>
|
<MDBCardTitle>1. Generate report</MDBCardTitle>
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
</MDBCard>
|
</MDBCard>
|
||||||
</MDBCol>
|
</MDBCol>
|
||||||
|
|
||||||
<MDBCol md="12" v-if="!summaryLoaded">
|
<MDBCol md="12" v-if="!report">
|
||||||
<MDBCard>
|
<MDBCard>
|
||||||
<MDBCardBody>
|
<MDBCardBody>
|
||||||
<MDBCardTitle>2. Upload report</MDBCardTitle>
|
<MDBCardTitle>2. Upload report</MDBCardTitle>
|
||||||
@@ -39,75 +39,20 @@
|
|||||||
</MDBCard>
|
</MDBCard>
|
||||||
</MDBCol>
|
</MDBCol>
|
||||||
|
|
||||||
<MDBCol md="12" v-if="summaryLoaded">
|
<MDBCol md="12" v-if="report">
|
||||||
<MDBCard>
|
<ReportDetails :meta="report.meta"/>
|
||||||
<MDBCardBody>
|
|
||||||
<MDBCardTitle class="d-flex">
|
|
||||||
<span class="me-1">Summary</span>
|
|
||||||
<MDBBadge color="primary">/proc/stat</MDBBadge>
|
|
||||||
</MDBCardTitle>
|
|
||||||
<MDBCardText>
|
|
||||||
This section contains raw data from <code>/proc/stat</code>, visualised and with calculated relative (percent) share of the total CPU time.
|
|
||||||
<ul>
|
|
||||||
<li><em>Current run</em> represents the data between the start and the end of the report generation.</li>
|
|
||||||
<li><em>All time</em> represents absolute values from the last system restart until the end of the report generation.</li>
|
|
||||||
</ul>
|
|
||||||
</MDBCardText>
|
|
||||||
<MDBTabs v-model="summaryTab">
|
|
||||||
<MDBTabNav tabsClasses="mb-3">
|
|
||||||
<MDBTabItem tabId="summary-current-run" href="summary-current-run">Current run</MDBTabItem>
|
|
||||||
<MDBTabItem tabId="summary-all-time" href="summary-all-time">All time</MDBTabItem>
|
|
||||||
</MDBTabNav>
|
|
||||||
<MDBTabContent>
|
|
||||||
<MDBTabPane tabId="summary-current-run">
|
|
||||||
<Summary :key="summaryTab" :stats="summaryStats" :chart-series="summarySeries"/>
|
|
||||||
</MDBTabPane>
|
|
||||||
<MDBTabPane tabId="summary-all-time">
|
|
||||||
<Summary :key="summaryTab" :stats="summaryStatsAll" :chart-series="summarySeriesAll"/>
|
|
||||||
</MDBTabPane>
|
|
||||||
</MDBTabContent>
|
|
||||||
</MDBTabs>
|
|
||||||
</MDBCardBody>
|
|
||||||
</MDBCard>
|
|
||||||
</MDBCol>
|
</MDBCol>
|
||||||
|
|
||||||
<MDBCol md="12" v-if="summaryLoaded">
|
<MDBCol md="12" v-if="report">
|
||||||
<MDBCard>
|
<ReportSummary :report="report"/>
|
||||||
<MDBCardBody>
|
|
||||||
<MDBCardTitle class="d-flex">
|
|
||||||
<span class="me-1">History</span>
|
|
||||||
<MDBBadge color="primary">/proc/stat</MDBBadge>
|
|
||||||
</MDBCardTitle>
|
|
||||||
<MDBCardText>
|
|
||||||
This section contains data (currently <code>{{ historyTab.replace('history-', '') }}</code>) changes over time represented as a relative (percent) share of the total CPU time.
|
|
||||||
</MDBCardText>
|
|
||||||
<MDBTabs v-model="historyTab">
|
|
||||||
<MDBTabNav tabsClasses="mb-3">
|
|
||||||
<MDBTabItem v-for="label in dataLabels" :key="label" :tabId="`history-${label}`" :href="`history-${label}`">{{ label }}</MDBTabItem>
|
|
||||||
</MDBTabNav>
|
|
||||||
<MDBTabContent>
|
|
||||||
<MDBTabPane v-for="label in dataLabels" :key="label" :tabId="`history-${label}`">
|
|
||||||
<History :key="historyTab" :name="label" :chart-series="historySeries[label]"/>
|
|
||||||
</MDBTabPane>
|
|
||||||
</MDBTabContent>
|
|
||||||
</MDBTabs>
|
|
||||||
</MDBCardBody>
|
|
||||||
</MDBCard>
|
|
||||||
</MDBCol>
|
</MDBCol>
|
||||||
|
|
||||||
<MDBCol md="12" v-if="summaryLoaded">
|
<MDBCol md="12" v-if="report">
|
||||||
<MDBCard>
|
<ReportHistoryProcStat :report="report"/>
|
||||||
<MDBCardBody>
|
</MDBCol>
|
||||||
<MDBCardTitle class="d-flex">
|
|
||||||
<span class="me-1">History</span>
|
<MDBCol md="12" v-if="report">
|
||||||
<MDBBadge color="primary">/proc/meminfo</MDBBadge>
|
<ReportHistoryProcMeminfo :report="report"/>
|
||||||
</MDBCardTitle>
|
|
||||||
<MDBCardText>
|
|
||||||
This section contains memory usage changes over time.
|
|
||||||
</MDBCardText>
|
|
||||||
<code>TODO</code>
|
|
||||||
</MDBCardBody>
|
|
||||||
</MDBCard>
|
|
||||||
</MDBCol>
|
</MDBCol>
|
||||||
|
|
||||||
</MDBRow>
|
</MDBRow>
|
||||||
@@ -116,33 +61,19 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {
|
import {MDBCard, MDBCardBody, MDBCardText, MDBCardTitle, MDBCol, MDBContainer, MDBFile, MDBNavbar, MDBNavbarItem, MDBNavbarNav, MDBRow} from 'mdb-vue-ui-kit';
|
||||||
MDBBadge,
|
import ReportSummary from "@/components/report/summary/ReportSummary";
|
||||||
MDBCard,
|
import ReportHistoryProcMeminfo from "@/components/report/history/ReportHistoryProcMeminfo";
|
||||||
MDBCardBody,
|
import ReportHistoryProcStat from "@/components/report/history/ReportHistoryProcStat";
|
||||||
MDBCardText,
|
import ReportDetails from "@/components/report/ReportDetails";
|
||||||
MDBCardTitle,
|
|
||||||
MDBCol,
|
|
||||||
MDBContainer,
|
|
||||||
MDBFile,
|
|
||||||
MDBNavbar,
|
|
||||||
MDBNavbarItem,
|
|
||||||
MDBNavbarNav,
|
|
||||||
MDBRow,
|
|
||||||
MDBTabContent,
|
|
||||||
MDBTabItem,
|
|
||||||
MDBTabNav,
|
|
||||||
MDBTabPane,
|
|
||||||
MDBTabs
|
|
||||||
} from 'mdb-vue-ui-kit';
|
|
||||||
import Summary from "@/components/Summary";
|
|
||||||
import History from "@/components/History";
|
|
||||||
import {ref} from "vue";
|
import {ref} from "vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
History,
|
ReportDetails,
|
||||||
Summary,
|
ReportHistoryProcStat,
|
||||||
|
ReportHistoryProcMeminfo,
|
||||||
|
ReportSummary,
|
||||||
MDBNavbar,
|
MDBNavbar,
|
||||||
MDBNavbarNav,
|
MDBNavbarNav,
|
||||||
MDBNavbarItem,
|
MDBNavbarItem,
|
||||||
@@ -153,100 +84,30 @@ export default {
|
|||||||
MDBFile,
|
MDBFile,
|
||||||
MDBRow,
|
MDBRow,
|
||||||
MDBCol,
|
MDBCol,
|
||||||
MDBTabs,
|
MDBCardText
|
||||||
MDBTabNav,
|
|
||||||
MDBTabItem,
|
|
||||||
MDBTabContent,
|
|
||||||
MDBTabPane,
|
|
||||||
MDBCardText,
|
|
||||||
MDBBadge
|
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
msg: String
|
msg: String
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
files: async function (value) {
|
files: async function (value) {
|
||||||
this.rawData = (await this.fileToString(value[0])).split(/\r?\n/).map(l => l.split(" "));
|
let formData = new FormData();
|
||||||
const firstLineData = this.rawData[0].slice(1).map(i => parseInt(i));
|
formData.append('file', value[0]);
|
||||||
const lastLineData = this.rawData[this.rawData.length - 1].slice(1).map(i => parseInt(i));
|
this.report = await this.axios.post('/v1/parse', formData, {headers: {'Content-Type': 'multipart/form-data'}})
|
||||||
// update summary
|
.then((response) => response.data)
|
||||||
this.summarySeriesAll = lastLineData;
|
.catch((error) => console.log(error));
|
||||||
this.summarySeries = lastLineData.map((i, index) => i - firstLineData[index]);
|
|
||||||
this.summaryLoaded = true;
|
|
||||||
// update history
|
|
||||||
this.dataLabels.forEach((label, index) => {
|
|
||||||
this.historySeries[label] = this.calculateHistory(this.rawData, index);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
summarySeries: function (value) {
|
|
||||||
this.summaryStats = this.calculateSummaryStats(value);
|
|
||||||
},
|
|
||||||
summarySeriesAll: function (value) {
|
|
||||||
this.summaryStatsAll = this.calculateSummaryStats(value);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup: function () {
|
setup: function () {
|
||||||
return {
|
return {
|
||||||
dataLabels: ['user', 'nice', 'system', 'idle', 'iowait', 'irq', 'softirq', 'steal', 'guest', 'guest_nice'],
|
|
||||||
appUrl: process.env.VUE_APP_URL
|
appUrl: process.env.VUE_APP_URL
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
files: ref([]),
|
files: ref([]),
|
||||||
rawData: undefined,
|
report: ref(),
|
||||||
// summary
|
|
||||||
summaryTab: ref('summary-current-run'),
|
|
||||||
summaryLoaded: false,
|
|
||||||
summaryStats: [],
|
|
||||||
summaryStatsAll: [],
|
|
||||||
summarySeries: [],
|
|
||||||
summarySeriesAll: [],
|
|
||||||
// steal
|
|
||||||
historyTab: ref('history-steal'),
|
|
||||||
historySeries: {},
|
|
||||||
};
|
};
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
fileToString(file) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.readAsText(file, "UTF-8");
|
|
||||||
reader.onload = event => resolve(event.target.result)
|
|
||||||
reader.onerror = event => reject(event);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
calculateSummaryStats(data) {
|
|
||||||
const dataTotal = data.reduce((a, b) => a + b, 0);
|
|
||||||
let stats = [];
|
|
||||||
this.dataLabels.forEach((label, index) => {
|
|
||||||
stats[index] = {
|
|
||||||
name: label,
|
|
||||||
value: data[index],
|
|
||||||
percent: (data[index] / dataTotal) * 100
|
|
||||||
}
|
|
||||||
});
|
|
||||||
stats.sort((a, b) => {
|
|
||||||
return (a.value > b.value) ? -1 : 1;
|
|
||||||
});
|
|
||||||
return stats;
|
|
||||||
},
|
|
||||||
calculateHistory(rawData, index) {
|
|
||||||
let history = [];
|
|
||||||
let lastTotal = 0;
|
|
||||||
let lastValue = 0;
|
|
||||||
rawData.forEach(line => {
|
|
||||||
const date = new Date(line[0]);
|
|
||||||
const rawValue = parseInt(line[index + 1]);
|
|
||||||
const value = rawValue - lastValue;
|
|
||||||
const rawTotal = line.slice(1).map(i => parseInt(i)).reduce((a, b) => a + b, 0);
|
|
||||||
const total = rawTotal - lastTotal;
|
|
||||||
history.push([date, ((value / total) * 100)])
|
|
||||||
lastTotal = rawTotal;
|
|
||||||
lastValue = rawValue;
|
|
||||||
})
|
|
||||||
return history;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
53
frontend/src/components/report/ReportDetails.vue
Normal file
53
frontend/src/components/report/ReportDetails.vue
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<template>
|
||||||
|
<MDBCard>
|
||||||
|
<MDBCardBody>
|
||||||
|
<MDBCardTitle class="d-flex">
|
||||||
|
<span class="me-1">Report from {{ new Date().toLocaleString() }}</span>
|
||||||
|
<MDBBadge color="primary">OT-v1.0</MDBBadge>
|
||||||
|
</MDBCardTitle>
|
||||||
|
<MDBRow>
|
||||||
|
<MDBCol md="12">
|
||||||
|
<MDBTable class="mb-0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">#</th>
|
||||||
|
<th scope="col">Value</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="key in Object.keys(meta)" :key="key">
|
||||||
|
<th scope="row">{{ key }}</th>
|
||||||
|
<td>{{ meta[key] }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</MDBTable>
|
||||||
|
</MDBCol>
|
||||||
|
</MDBRow>
|
||||||
|
</MDBCardBody>
|
||||||
|
</MDBCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {MDBBadge, MDBCard, MDBCardBody, MDBCardTitle, MDBTable, MDBRow, MDBCol} from "mdb-vue-ui-kit";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
MDBCard,
|
||||||
|
MDBCardBody,
|
||||||
|
MDBCardTitle,
|
||||||
|
MDBTable,
|
||||||
|
MDBBadge,
|
||||||
|
MDBRow,
|
||||||
|
MDBCol
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
meta: Object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
table th, table td {
|
||||||
|
padding: .2em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<apexchart type="line" height="300" :options="chartOptions" :series="[{name: name, data: chartSeries}]"></apexchart>
|
<apexchart type="line" height="300" :options="chartOptions" :series="chartSeries"></apexchart>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -7,20 +7,24 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
name: {
|
chartSeries: {
|
||||||
type: String
|
type: Array
|
||||||
|
},
|
||||||
|
yFormatter: {
|
||||||
|
type: Function,
|
||||||
|
default: function (value) {
|
||||||
|
return value.toFixed(3) + '%';
|
||||||
|
}
|
||||||
},
|
},
|
||||||
chartOptions: {
|
chartOptions: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: function () {
|
default: function (props) {
|
||||||
return {
|
return {
|
||||||
fill: {type: 'solid'},
|
fill: {type: 'solid'},
|
||||||
xaxis: {type: 'datetime'},
|
xaxis: {type: 'datetime'},
|
||||||
yaxis: {
|
yaxis: {
|
||||||
labels: {
|
labels: {
|
||||||
formatter: function (value) {
|
formatter: props.yFormatter
|
||||||
return value.toFixed(3) + '%';
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
@@ -34,9 +38,6 @@ export default {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
chartSeries: {
|
|
||||||
type: Array
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
<template>
|
||||||
|
<MDBCard>
|
||||||
|
<MDBCardBody>
|
||||||
|
<MDBCardTitle class="d-flex">
|
||||||
|
<span class="me-1">History</span>
|
||||||
|
<MDBBadge color="primary">/proc/meminfo</MDBBadge>
|
||||||
|
</MDBCardTitle>
|
||||||
|
<MDBCardText>
|
||||||
|
This section contains memory usage changes over time.
|
||||||
|
</MDBCardText>
|
||||||
|
<!--suppress RequiredAttributes -->
|
||||||
|
<MDBTabs v-model="historyTab">
|
||||||
|
<MDBTabNav tabsClasses="mb-3">
|
||||||
|
<MDBTabItem tab-id="history-mem" href="history-mem">Memory</MDBTabItem>
|
||||||
|
<MDBTabItem tab-id="history-swap" href="history-swap">Swap</MDBTabItem>
|
||||||
|
</MDBTabNav>
|
||||||
|
<MDBTabContent>
|
||||||
|
<MDBTabPane tab-id="history-mem">
|
||||||
|
<ReportHistoryPage :key="historyTab" :chart-series="memSeries" :y-formatter="yFormatter"/>
|
||||||
|
</MDBTabPane>
|
||||||
|
<MDBTabPane tab-id="history-swap">
|
||||||
|
<ReportHistoryPage :key="historyTab" :chart-series="swapSeries" :y-formatter="yFormatter"/>
|
||||||
|
</MDBTabPane>
|
||||||
|
</MDBTabContent>
|
||||||
|
</MDBTabs>
|
||||||
|
</MDBCardBody>
|
||||||
|
</MDBCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {MDBBadge, MDBCard, MDBCardBody, MDBCardText, MDBCardTitle, MDBTabContent, MDBTabItem, MDBTabNav, MDBTabPane, MDBTabs} from "mdb-vue-ui-kit";
|
||||||
|
import ReportHistoryPage from "@/components/report/history/ReportHistoryPage";
|
||||||
|
import {ref} from "vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
ReportHistoryPage,
|
||||||
|
MDBCard,
|
||||||
|
MDBCardBody,
|
||||||
|
MDBCardTitle,
|
||||||
|
MDBCardText,
|
||||||
|
MDBBadge,
|
||||||
|
MDBTabs,
|
||||||
|
MDBTabNav,
|
||||||
|
MDBTabItem,
|
||||||
|
MDBTabContent,
|
||||||
|
MDBTabPane,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
report: {
|
||||||
|
type: Object
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
|
||||||
|
const memMetrics = ['mem/total', 'mem/free', 'mem/available', 'mem/buffers', 'mem/cached'];
|
||||||
|
const swapMetrics = ['swap/cached', 'swap/total', 'swap/free'];
|
||||||
|
|
||||||
|
const header = this.report.header;
|
||||||
|
const data = this.report.data;
|
||||||
|
const timeIndex = header.indexOf("timestamp");
|
||||||
|
|
||||||
|
const memSeries = memMetrics.map(metric => {
|
||||||
|
const index = header.indexOf(metric);
|
||||||
|
return {name: metric, data: data.map(entry => [new Date(entry[timeIndex] * 1000), entry[index]])}
|
||||||
|
})
|
||||||
|
|
||||||
|
const swapSeries = swapMetrics.map(metric => {
|
||||||
|
const index = header.indexOf(metric);
|
||||||
|
return {name: metric, data: data.map(entry => [new Date(entry[timeIndex] * 1000), entry[index]])}
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
historyTab: ref('history-mem'),
|
||||||
|
memSeries,
|
||||||
|
swapSeries
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
yFormatter(value) {
|
||||||
|
return this.formatBytes(value * 1024);
|
||||||
|
},
|
||||||
|
formatBytes(value) {
|
||||||
|
let b = 0, c = parseInt(value, 10) || 0;
|
||||||
|
for (; 1024 <= c && ++b;) c /= 1024;
|
||||||
|
return c.toFixed(10 > c && 0 < b ? 1 : 0) + " " + ["bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"][b]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
<template>
|
||||||
|
<MDBCard>
|
||||||
|
<MDBCardBody>
|
||||||
|
<MDBCardTitle class="d-flex">
|
||||||
|
<span class="me-1">History</span>
|
||||||
|
<MDBBadge color="primary">/proc/stat</MDBBadge>
|
||||||
|
</MDBCardTitle>
|
||||||
|
<MDBCardText>
|
||||||
|
This section contains data (currently <code>{{ historyTab.replace('history-', '') }}</code>) changes over time represented as a relative (percent) share of the total CPU time.
|
||||||
|
</MDBCardText>
|
||||||
|
<!--suppress RequiredAttributes -->
|
||||||
|
<MDBTabs v-model="historyTab">
|
||||||
|
<MDBTabNav tabsClasses="mb-3">
|
||||||
|
<MDBTabItem v-for="series in historySeries" :key="series.name" :tabId="`history-${series.name}`" :href="`history-${series.name}`">{{ series.name }}</MDBTabItem>
|
||||||
|
</MDBTabNav>
|
||||||
|
<MDBTabContent>
|
||||||
|
<MDBTabPane v-for="series in historySeries" :key="series.name" :tabId="`history-${series.name}`">
|
||||||
|
<ReportHistoryPage :key="historyTab" :name="series.name" :chart-series="[series]"/>
|
||||||
|
</MDBTabPane>
|
||||||
|
</MDBTabContent>
|
||||||
|
</MDBTabs>
|
||||||
|
</MDBCardBody>
|
||||||
|
</MDBCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {MDBBadge, MDBCard, MDBCardBody, MDBCardText, MDBCardTitle, MDBTabContent, MDBTabItem, MDBTabNav, MDBTabPane, MDBTabs} from "mdb-vue-ui-kit";
|
||||||
|
import ReportHistoryPage from "@/components/report/history/ReportHistoryPage";
|
||||||
|
import {ref} from "vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
ReportHistoryPage,
|
||||||
|
MDBCard,
|
||||||
|
MDBCardBody,
|
||||||
|
MDBCardTitle,
|
||||||
|
MDBCardText,
|
||||||
|
MDBTabs,
|
||||||
|
MDBTabNav,
|
||||||
|
MDBTabItem,
|
||||||
|
MDBTabContent,
|
||||||
|
MDBTabPane,
|
||||||
|
MDBBadge,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
report: {
|
||||||
|
type: Object
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: function() {
|
||||||
|
|
||||||
|
const metrics = ['cpu/user', 'cpu/nice', 'cpu/system', 'cpu/idle', 'cpu/iowait', 'cpu/irq', 'cpu/softirq', 'cpu/steal', 'cpu/guest', 'cpu/guest_nice'];
|
||||||
|
const header = this.report.header;
|
||||||
|
const data = this.report.data;
|
||||||
|
|
||||||
|
const timeIndex = header.indexOf("timestamp");
|
||||||
|
const cpuDataSums = data
|
||||||
|
.map(row => this.rowSlice(row, header, metrics))
|
||||||
|
.map(row => row.reduce((a, b) => a + b, 0))
|
||||||
|
|
||||||
|
const series = metrics.map(metric => {
|
||||||
|
const index = header.indexOf(metric);
|
||||||
|
return {
|
||||||
|
name: metric.replace('cpu/', ''),
|
||||||
|
data: data.map((entry, i) => [new Date(entry[timeIndex] * 1000), (entry[index] / cpuDataSums[i] * 100)])
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
historyTab: ref('history-steal'),
|
||||||
|
historySeries: series
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
rowSlice(row, header, metrics) {
|
||||||
|
return row.filter((value, index) => {
|
||||||
|
return metrics.includes(header[index]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
100
frontend/src/components/report/summary/ReportSummary.vue
Normal file
100
frontend/src/components/report/summary/ReportSummary.vue
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
<template>
|
||||||
|
<MDBCard>
|
||||||
|
<MDBCardBody>
|
||||||
|
<MDBCardTitle class="d-flex">
|
||||||
|
<span class="me-1">Summary</span>
|
||||||
|
<MDBBadge color="primary">/proc/stat</MDBBadge>
|
||||||
|
</MDBCardTitle>
|
||||||
|
<MDBCardText>
|
||||||
|
This section contains raw data from <code>/proc/stat</code>, visualised and with calculated relative (percent) share of the total CPU time.
|
||||||
|
<ul>
|
||||||
|
<li><em>Current run</em> represents the data between the start and the end of the report generation.</li>
|
||||||
|
<li><em>All time</em> represents absolute values from the last system restart until the end of the report generation.</li>
|
||||||
|
</ul>
|
||||||
|
</MDBCardText>
|
||||||
|
<!--suppress RequiredAttributes -->
|
||||||
|
<MDBTabs v-model="summaryTab">
|
||||||
|
<MDBTabNav tabsClasses="mb-3">
|
||||||
|
<MDBTabItem tabId="summary-current-run" href="summary-current-run">Current run</MDBTabItem>
|
||||||
|
<MDBTabItem tabId="summary-all-time" href="summary-all-time">All time</MDBTabItem>
|
||||||
|
</MDBTabNav>
|
||||||
|
<MDBTabContent>
|
||||||
|
<MDBTabPane tabId="summary-current-run">
|
||||||
|
<ReportSummaryPage :key="summaryTab" :stats="summaryCurrent.stats" :chart-series="summaryCurrent.series"/>
|
||||||
|
</MDBTabPane>
|
||||||
|
<MDBTabPane tabId="summary-all-time">
|
||||||
|
<ReportSummaryPage :key="summaryTab" :stats="summaryAll.stats" :chart-series="summaryAll.series"/>
|
||||||
|
</MDBTabPane>
|
||||||
|
</MDBTabContent>
|
||||||
|
</MDBTabs>
|
||||||
|
</MDBCardBody>
|
||||||
|
</MDBCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {MDBBadge, MDBCard, MDBCardBody, MDBCardText, MDBCardTitle, MDBTabContent, MDBTabItem, MDBTabNav, MDBTabPane, MDBTabs} from "mdb-vue-ui-kit";
|
||||||
|
import ReportSummaryPage from "@/components/report/summary/ReportSummaryPage";
|
||||||
|
import {ref} from "vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
MDBCard,
|
||||||
|
MDBCardBody,
|
||||||
|
MDBCardTitle,
|
||||||
|
MDBCardText,
|
||||||
|
MDBTabs,
|
||||||
|
MDBTabNav,
|
||||||
|
MDBTabItem,
|
||||||
|
MDBTabContent,
|
||||||
|
MDBTabPane,
|
||||||
|
MDBBadge,
|
||||||
|
ReportSummaryPage,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
report: {
|
||||||
|
type: Object
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
|
||||||
|
const metrics = ['cpu/user', 'cpu/nice', 'cpu/system', 'cpu/idle', 'cpu/iowait', 'cpu/irq', 'cpu/softirq', 'cpu/steal', 'cpu/guest', 'cpu/guest_nice'];
|
||||||
|
const header = this.report.header;
|
||||||
|
const data = this.report.data;
|
||||||
|
|
||||||
|
return {
|
||||||
|
summaryTab: ref('summary-current-run'),
|
||||||
|
summaryCurrent: this.getSummaryCurrent(metrics, header, data),
|
||||||
|
summaryAll: this.getSummaryAll(metrics, header, data),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getSummaryCurrent(metrics, header, data) {
|
||||||
|
const firstRow = data[0];
|
||||||
|
const lastRow = data[data.length - 1];
|
||||||
|
const dataRow = lastRow.map((value, index) => value - firstRow[index]);
|
||||||
|
return this.getSummary(metrics, header, dataRow)
|
||||||
|
},
|
||||||
|
getSummaryAll(metrics, header, data) {
|
||||||
|
const dataRow = data[data.length - 1];
|
||||||
|
return this.getSummary(metrics, header, dataRow)
|
||||||
|
},
|
||||||
|
getSummary(metrics, header, dataRow) {
|
||||||
|
const stats = metrics.map(metric => {
|
||||||
|
const name = metric.replace('cpu/', '');
|
||||||
|
const value = dataRow[header.indexOf(metric)];
|
||||||
|
const percent = value / this.rowSlice(dataRow, header, metrics).reduce((a, b) => a + b, 0) * 100;
|
||||||
|
return {name, value, percent: (Number.isNaN(percent) ? 0 : percent)};
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
series: stats.map(stat => stat.value),
|
||||||
|
stats: stats.sort((a, b) => (a.value > b.value) ? -1 : 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rowSlice(row, header, metrics) {
|
||||||
|
return row.filter((value, index) => {
|
||||||
|
return metrics.includes(header[index]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -4,10 +4,12 @@ import {FontAwesomeIcon, FontAwesomeLayers} from '@fortawesome/vue-fontawesome'
|
|||||||
import {faGithub} from "@fortawesome/free-brands-svg-icons/faGithub";
|
import {faGithub} from "@fortawesome/free-brands-svg-icons/faGithub";
|
||||||
import {faExclamationTriangle} from "@fortawesome/free-solid-svg-icons/faExclamationTriangle";
|
import {faExclamationTriangle} from "@fortawesome/free-solid-svg-icons/faExclamationTriangle";
|
||||||
import {faQuestionCircle} from "@fortawesome/free-solid-svg-icons/faQuestionCircle";
|
import {faQuestionCircle} from "@fortawesome/free-solid-svg-icons/faQuestionCircle";
|
||||||
|
import {faCheck} from "@fortawesome/free-solid-svg-icons/faCheck";
|
||||||
|
|
||||||
library.add(faGithub);
|
library.add(faGithub);
|
||||||
library.add(faExclamationTriangle);
|
library.add(faExclamationTriangle);
|
||||||
library.add(faQuestionCircle);
|
library.add(faQuestionCircle);
|
||||||
|
library.add(faCheck);
|
||||||
|
|
||||||
export default (app) => {
|
export default (app) => {
|
||||||
app.component('font-awesome-icon', FontAwesomeIcon);
|
app.component('font-awesome-icon', FontAwesomeIcon);
|
||||||
|
|||||||
Reference in New Issue
Block a user