Files
raven-client/ayanova/src/views/ops-metrics.vue
2021-02-10 15:53:45 +00:00

529 lines
14 KiB
Vue

<template>
<v-row v-if="this.formState.ready" v-resize="onResize">
<gz-error :error-box-message="formState.errorBoxMessage"></gz-error>
<v-col cols="12" sm="6" lg="4" xl="3">
<v-select
v-model="selectedTimePeriod"
:items="selectLists.dateFilterTokens"
item-text="name"
item-value="id"
append-outer-icon="$ayiSync"
@click:append-outer="getDataFromApi"
@input="timePeriodChanged"
data-cy="selectedTimePeriod"
></v-select>
</v-col>
<v-tabs v-model="tab" @change="tabChanged">
<v-tabs-slider></v-tabs-slider>
<v-tab>{{ $ay.t("MetricCPUMemory") }}</v-tab>
<v-tab>{{ $ay.t("Database") }}</v-tab>
<v-tab>{{ $ay.t("MetricFileStorage") }}</v-tab>
<v-tabs-items v-model="tab">
<v-tab-item>
<v-col cols="12">
<gz-chart-line
:chart-data="memAllChartData"
:options="timeLineChartOptions"
class="my-12"
/>
</v-col>
<v-col cols="12">
<gz-chart-line
:chart-data="cpuChartData"
:options="timeLineChartOptions"
class="my-12"
/>
</v-col>
</v-tab-item>
<v-tab-item>
<v-col cols="12">
<gz-chart-line
:chart-data="dbChartData"
:options="timeLineChartOptions"
class="my-12"
/>
</v-col>
<v-col cols="12" lg="10" xl="8">
<gz-chart-bar-horizontal
:chart-data="dbTopTablesChartData"
:options="{
responsive: true,
scales: {
xAxes: [{ gridLines: { display: true } }],
yAxes: [{ gridLines: { display: false } }]
}
}"
class="my-12"
/>
</v-col>
</v-tab-item>
<v-tab-item>
<v-col cols="12">
<gz-chart-line
:chart-data="fileSizeChartData"
:options="timeLineChartOptions"
class="my-12"
/>
</v-col>
<v-col cols="12">
<gz-chart-line
:chart-data="attachmentCountChartData"
:options="timeLineChartOptions"
class="my-12"
/>
</v-col>
</v-tab-item>
</v-tabs-items>
</v-tabs>
</v-row>
</template>
<script>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Xeslint-disable */
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//https://blog.hubspot.com/marketing/types-of-graphs-for-data-visualization
//https://medium.com/javascript-in-plain-english/exploring-chart-js-e3ba70b07aa4
import relativeDatefilterCalculator from "../api/relative-date-filter-calculator.js";
import Palette from "../api/palette";
const FORM_KEY = "ops-metrics";
export default {
async created() {
let vm = this;
try {
await initForm(vm);
window.$gz.eventBus.$on("menu-click", clickHandler);
generateMenu(vm);
await vm.getDataFromApi();
} catch (err) {
vm.formState.ready = true;
window.$gz.errorHandler.handleFormError(err, vm);
}
},
beforeDestroy() {
window.$gz.eventBus.$off("menu-click", clickHandler);
},
data() {
return {
storage: { isnew: true },
memcpu: { isnew: true },
db: { isnew: true },
timeLineChartOptions: {
responsive: true,
maintainAspectRatio: false,
scales: {
xAxes: [
{
type: "time",
// distribution: "linear",
gridLines: {
drawOnChartArea: false
}
}
],
yAxes: [
{
gridLines: {
drawOnChartArea: false
},
ticks: {
beginAtZero: true
}
}
]
}
},
selectedTimePeriod: "*past6hours*",
selectLists: {
dateFilterTokens: []
},
lastFetchBreakPoint: null,
tab: 0,
formState: {
ready: false,
loading: false,
errorBoxMessage: null,
appError: null,
serverError: {}
}
};
},
methods: {
onResize() {
let breakPoint = "xl";
if (window.innerWidth < 1904) {
breakPoint = "lg";
}
if (window.innerWidth < 1264) {
breakPoint = "md";
}
if (window.innerWidth < 960) {
breakPoint = "sm";
}
if (window.innerWidth < 600) {
breakPoint = "xs";
}
if (breakPoint != this.lastFetchBreakPoint) {
this.getDataFromApi(breakPoint);
}
},
timePeriodChanged: function() {
this.getDataFromApi();
},
tabChanged: function(tab) {
let vm = this;
if (vm[tabIndexToRoute(vm.tab)].isnew) {
vm.getDataFromApi();
}
},
async getDataFromApi(breakPoint) {
let vm = this;
if (vm.formState.loading) {
return;
}
let filterDates = relativeDatefilterCalculator.tokenToDates(
vm.selectedTimePeriod
);
vm.formState.loading = true;
if (breakPoint == null) {
breakPoint = vm.$vuetify.breakpoint.name;
}
//##########################################################################################################################################
//Visually, 200 points max looks best on full screen widths and 40 on galaxy s9 minimum standard
//there is no relevant loss of fidelity with this downsampling
let max = 200;
//https://vuetifyjs.com/en/customization/breakpoints/#breakpoint-service-object
//Note: used geometric progression of 1.5 for this
//40*1.5=60, 60*1.5=90 etc etc etc
//wanted it to fit between 40 at lowest end and 200 at highest end
switch (breakPoint) {
case "xs":
max = 40;
break;
case "sm":
max = 60;
break;
case "md":
max = 90;
break;
case "lg":
max = 135;
break;
case "xl":
max = 200;
break;
default:
max = 200;
}
let url =
"server-metric/" +
tabIndexToRoute(vm.tab) +
"?maxRecords=" +
max +
"&tsStart=" +
filterDates.after +
"&tsEnd=" +
filterDates.before;
window.$gz.form.deleteAllErrorBoxErrors(vm);
try {
let res = await window.$gz.api.get(url);
if (res.error) {
if (res.error.code == "2010") {
window.$gz.form.handleObjectNotFound(vm);
}
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
vm[tabIndexToRoute(vm.tab)] = res.data;
vm.lastFetchBreakPoint = breakPoint;
window.$gz.form.setFormState({
vm: vm,
dirty: false,
valid: true,
loading: false
});
vm.formState.ready = true;
}
} catch (error) {
window.$gz.form.setFormState({
vm: vm,
loading: false
});
window.$gz.errorHandler.handleFormError(error, vm);
}
}
},
computed: {
cpuChartData() {
return {
datasets: [
{
label: "CPU %",
borderColor: Palette.color.soft_sand,
fill: false,
radius: 0,
hoverRadius: 10,
hitRadius: 4,
data: this.memcpu.cpu
}
]
};
},
dbChartData() {
return {
datasets: [
{
label: this.$ay.t("MetricDBSize"),
borderColor: Palette.color.blue,
fill: false,
radius: 0,
hoverRadius: 10,
hitRadius: 4,
data: this.db.totalSize
}
]
};
},
dbTopTablesChartData() {
// debugger;
if (!this.db.topTables) {
return { labels: [], datasets: [] };
}
return {
// These labels appear in the legend and in the tooltips when hovering different arcs
//_.map(users, 'user');
//de-lodash
// labels: window.$gz. _.map(this.db.topTables, "name"),
labels: this.db.topTables.map(z => z.name),
datasets: [
{
label: this.$ay.t("MetricTopTablesSize"),
//de-lodash
// data: window.$gz. _.map(this.db.topTables, "value"),
data: this.db.topTables.map(z => z.value),
backgroundColor: Palette.getSoftPaletteArray(
this.db.topTables ? this.db.topTables.length : 3
),
minBarLength: 5
}
]
};
},
memAllChartData() {
return {
datasets: [
{
label: this.$ay.t("MetricAllocatedMemory"),
borderColor: Palette.color.soft_brown_darker,
fill: false,
radius: 0,
hoverRadius: 10,
hitRadius: 4,
data: this.memcpu.allocated
},
{
label: this.$ay.t("MetricWorkingSet"),
borderColor: Palette.color.soft_green,
//borderWidth:4,
// pointStyle: "rectRot",
radius: 0,
hoverRadius: 10,
hitRadius: 4,
// borderDash: [20, 3, 3, 3, 3, 3, 3, 3],
fill: false,
data: this.memcpu.workingSet
},
{
label: this.$ay.t("MetricPrivateBytes"),
borderColor: Palette.color.soft_deep_blue,
fill: false,
radius: 0,
hoverRadius: 10,
hitRadius: 4,
data: this.memcpu.privateBytes
}
]
};
},
fileSizeChartData() {
return {
datasets: [
{
label: this.$ay.t("MetricAttachmentsMB"),
borderColor: Palette.color.purple,
fill: false,
radius: 0,
hoverRadius: 10,
hitRadius: 4,
data: this.storage.attachmentFileSize
},
{
label: this.$ay.t("MetricBackupMB"),
borderColor: Palette.color.orange,
fill: false,
radius: 0,
hoverRadius: 10,
hitRadius: 4,
data: this.storage.utilityFileSize
},
{
label: this.$ay.t("MetricAvailableDiskSpace"),
borderColor: Palette.color.green,
fill: false,
radius: 0,
hoverRadius: 10,
hitRadius: 4,
data: this.storage.attachmentFilesAvailableSpace
}
]
};
},
attachmentCountChartData() {
return {
datasets: [
{
label: this.$ay.t("MetricAttachmentsCount"),
borderColor: Palette.color.blue,
fill: false,
radius: 0,
hoverRadius: 10,
hitRadius: 4,
data: this.storage.attachmentFileCount
}
]
};
}
}
};
//////////////////////
//
//
function tabIndexToRoute(tabIndex) {
switch (tabIndex) {
case 0:
return "memcpu";
case 1:
return "db";
case 2:
return "storage";
}
}
//////////////////////
//
//
function generateMenu(vm) {
let menuOptions = {
isMain: true,
icon: "$ayiFileMedicalAlt",
title: "ServerMetrics",
helpUrl: "ops-metrics",
formData: {
ayaType: window.$gz.type.ServerMetrics
},
menuItems: [
// {
// title: "DEV_TEST_COLLECT",
// icon: "fa - bolt",
// surface: true,
// key: FORM_KEY + ":collect",
// vm: vm
// }
]
};
window.$gz.eventBus.$emit("menu-change", menuOptions);
}
/////////////////////////////
//
//
function clickHandler(menuItem) {
if (!menuItem) {
return;
}
let m = window.$gz.menu.parseMenuItem(menuItem);
if (m.owner == FORM_KEY && !m.disabled) {
switch (m.key) {
// case "collect":
// //trigger garbage collection
// window.$gz.api.get("server-metric/collect");
// break;
default:
window.$gz.eventBus.$emit(
"notify-warning",
FORM_KEY + "::context click: [" + m.key + "]"
);
}
}
}
/////////////////////////////////
//
//
async function initForm(vm) {
await fetchTranslatedText(vm);
await populateSelectionLists(vm);
}
/////////////////////////////////
//
//
function populateSelectionLists(vm) {
vm.selectLists.dateFilterTokens.push(
...[
{ name: vm.$ay.t("DateRangePast6Hours"), id: "*past6hours*" },
{ name: vm.$ay.t("DateRangePast24Hours"), id: "*past24hours*" },
{ name: vm.$ay.t("DateRangePast7Days"), id: "*past7days*" },
{ name: vm.$ay.t("DateRangePast30Days"), id: "*past30days*" },
{
name: vm.$ay.t("DateRangeInTheLastSixMonths"),
id: "*last6months*"
},
{ name: vm.$ay.t("DateRangePastYear"), id: "*pastyear*" }
]
);
}
//////////////////////////////////////////////////////////
//
// Ensures UI translated text is available
//
async function fetchTranslatedText(vm) {
await window.$gz.translation.cacheTranslations([
"DateRangePast6Hours",
"DateRangePast24Hours",
"DateRangePast7Days",
"DateRangePast30Days",
"DateRangeInTheLastSixMonths",
"DateRangePastYear",
"MetricFileStorage",
"MetricAttachmentsMB",
"MetricBackupMB",
"MetricAvailableDiskSpace",
"MetricAttachmentsCount",
"Database",
"MetricDBSize",
"MetricTopTablesSize",
"MetricCPUMemory",
"MetricAllocatedMemory",
"MetricWorkingSet",
"MetricPrivateBytes"
]);
}
</script>