Performance tab (no graphs yet)

This commit is contained in:
Aurora Lahtela 2022-08-20 10:30:24 +03:00
parent d39c377756
commit 5bd882036c
9 changed files with 294 additions and 4 deletions

View File

@ -104,9 +104,9 @@ public class PerformanceJSONCreator implements ServerTabJSONCreator<Map<String,
numbers.put("server_downtime_7d", timeAmount.apply(tpsDataWeek.serverDownTime()));
numbers.put("server_downtime_24h", timeAmount.apply(tpsDataDay.serverDownTime()));
numbers.put("players_30d", tpsDataMonth.averagePlayers());
numbers.put("players_7d", tpsDataWeek.averagePlayers());
numbers.put("players_24h", tpsDataDay.averagePlayers());
numbers.put("players_30d", format(tpsDataMonth.averagePlayers()));
numbers.put("players_7d", format(tpsDataWeek.averagePlayers()));
numbers.put("players_24h", format(tpsDataDay.averagePlayers()));
numbers.put("tps_30d", format(tpsDataMonth.averageTPS()));
numbers.put("tps_7d", format(tpsDataWeek.averageTPS()));
numbers.put("tps_24h", format(tpsDataDay.averageTPS()));

View File

@ -93,6 +93,9 @@ public enum HtmlLang implements Lang {
TITLE_30_DAYS("html.label.thirtyDays", "30 days"),
TITLE_AS_NUMBERS("html.label.asNumbers", "as Numbers"),
LABEL_AVG_TPS("html.label.averageTps", "Average TPS"),
LABEL_AVG_PLAYERS("html.label.averagePlayers", "Average Players"),
LABEL_AVG_CPU("html.label.averageCpuUsage", "Average CPU Usage"),
LABEL_AVG_RAM("html.label.averageRamUsage", "Average RAM Usage"),
LABEL_AVG_ENTITIES("html.label.averageEntities", "Average Entities"),
LABEL_AVG_CHUNKS("html.label.averageChunks", "Average Chunks"),
LABEL_LOW_TPS("html.label.lowTpsSpikes", "Low TPS Spikes"),

View File

@ -29,6 +29,7 @@ import PlayersPage from "./views/layout/PlayersPage";
import AllPlayers from "./views/players/AllPlayers";
import ServerGeolocations from "./views/server/ServerGeolocations";
import LoginPage from "./views/layout/LoginPage";
import ServerPerformance from "./views/server/ServerPerformance";
const SwaggerView = React.lazy(() => import("./views/SwaggerView"));
@ -87,7 +88,7 @@ function App() {
<Route path="retention" element={<></>}/>
<Route path="players" element={<ServerPlayers/>}/>
<Route path="geolocations" element={<ServerGeolocations/>}/>
<Route path="performance" element={<></>}/>
<Route path="performance" element={<ServerPerformance/>}/>
<Route path="plugins-overview" element={<></>}/>
<Route path="*" element={<ErrorView error={{
message: 'Unknown tab address, please correct the address',

View File

@ -0,0 +1,95 @@
import {useParams} from "react-router-dom";
import {useDataRequest} from "../../../../hooks/dataFetchHook";
import {fetchOptimizedPerformance} from "../../../../service/serverService";
import {ErrorViewBody} from "../../../../views/ErrorView";
import {useTranslation} from "react-i18next";
import {Card} from "react-bootstrap-v5";
import CardTabs from "../../../CardTabs";
import {faGears, faHdd, faMap, faMicrochip, faSignal, faTachometerAlt} from "@fortawesome/free-solid-svg-icons";
import React, {useEffect, useState} from "react";
import {ChartLoader} from "../../../navigation/Loader";
const PunchCardTab = ({data, loadingError}) => {
if (loadingError) return <ErrorViewBody error={loadingError}/>
if (!data) return <ChartLoader/>;
return <ChartLoader/>
}
function mapToDataSeries(performanceData) {
const playersOnline = [];
const tps = [];
const cpu = [];
const ram = [];
const entities = [];
const chunks = [];
const disk = [];
return new Promise((resolve => {
let i = 0;
const length = performanceData.length;
function processNextThousand() {
const to = Math.min(i + 1000, length);
for (i; i < to; i++) {
const entry = performanceData[i];
const date = entry[0];
playersOnline[i] = [date, entry[1]];
tps[i] = [date, entry[2]];
cpu[i] = [date, entry[3]];
ram[i] = [date, entry[4]];
entities[i] = [date, entry[5]];
chunks[i] = [date, entry[6]];
disk[i] = [date, entry[7]];
}
if (i >= length) {
resolve({playersOnline, tps, cpu, ram, entities, chunks, disk})
} else {
setTimeout(processNextThousand, 10);
}
}
processNextThousand();
}))
}
const PerformanceGraphsCard = () => {
const {t} = useTranslation();
const {identifier} = useParams();
const {data, loadingError} = useDataRequest(fetchOptimizedPerformance, [identifier]);
const [parsedData, setParsedData] = useState(undefined)
useEffect(() => {
if (data) {
mapToDataSeries(data).then(parsed => setParsedData(parsed))
}
}, [data]);
return <Card>
<CardTabs tabs={[
{
name: t('html.label.all'), icon: faGears, color: 'blue-grey', href: 'all',
element: <PunchCardTab data={parsedData} loadingError={loadingError}/>
}, {
name: t('html.label.tps'), icon: faTachometerAlt, color: 'red', href: 'tps',
element: <PunchCardTab data={parsedData} loadingError={loadingError}/>
}, {
name: t('html.label.cpuRam'), icon: faMicrochip, color: 'light-green', href: 'cpu-ram',
element: <PunchCardTab data={parsedData} loadingError={loadingError}/>
}, {
name: t('html.label.world'), icon: faMap, color: 'purple', href: 'world-load',
element: <PunchCardTab data={parsedData} loadingError={loadingError}/>
}, {
name: t('html.label.ping'), icon: faSignal, color: 'amber', href: 'ping',
element: <PunchCardTab data={parsedData} loadingError={loadingError}/>
}, {
name: t('html.label.diskSpace'), icon: faHdd, color: 'green', href: 'disk',
element: <PunchCardTab data={parsedData} loadingError={loadingError}/>
},
]}/>
</Card>
}
export default PerformanceGraphsCard;

View File

@ -0,0 +1,28 @@
import React from "react";
import InsightsFor30DaysCard from "../../common/InsightsFor30DaysCard";
import {useTranslation} from "react-i18next";
import Datapoint from "../../../Datapoint";
import {faDragon, faMap, faTachometerAlt, faUsers} from "@fortawesome/free-solid-svg-icons";
const PerformanceInsightsCard = ({data}) => {
const {t} = useTranslation();
if (!data) return <></>
return (
<InsightsFor30DaysCard>
<p>{t('html.label.duringLowTps')}</p>
<Datapoint name={t('html.label.average') + ' ' + t('html.label.players')} icon={faUsers} color="red"
value={data.low_tps_players} bold/>
<Datapoint name={t('html.label.averageEntities')} icon={faDragon} color="red"
value={data.low_tps_entities}/>
<Datapoint name={t('html.label.averageChunks')} icon={faMap} color="red"
value={data.low_tps_chunks}/>
<Datapoint name={t('html.label.averageCpuUsage')} icon={faTachometerAlt} color="red"
value={data.low_tps_entities}/>
<Datapoint name={t('html.label.averageTps')} icon={faTachometerAlt} color="red"
value={data.low_tps_tps}/>
</InsightsFor30DaysCard>
)
}
export default PerformanceInsightsCard;

View File

@ -0,0 +1,16 @@
import React from 'react';
import PerformanceAsNumbersTable from "../../../table/PerformanceAsNumbersTable";
import CardHeader from "../../CardHeader";
import {faBookOpen} from "@fortawesome/free-solid-svg-icons";
import {Card} from "react-bootstrap-v5";
const PerformanceAsNumbersCard = ({data}) => {
return (
<Card>
<CardHeader icon={faBookOpen} color="blue-grey" label={'html.label.performanceAsNumbers'}/>
<PerformanceAsNumbersTable data={data}/>
</Card>
)
};
export default PerformanceAsNumbersCard

View File

@ -0,0 +1,95 @@
import {useTranslation} from "react-i18next";
import {
faDragon,
faExclamationCircle,
faHdd,
faMap,
faMicrochip,
faPowerOff,
faTachometerAlt,
faUser
} from "@fortawesome/free-solid-svg-icons";
import React from "react";
import {TableRow} from "./TableRow";
import {FontAwesomeIcon as Fa} from "@fortawesome/react-fontawesome";
import {faEye} from "@fortawesome/free-regular-svg-icons";
import AsNumbersTable from "./AsNumbersTable";
const PerformanceAsNumbersTable = ({data}) => {
const {t} = useTranslation();
if (!data) return <></>;
return (
<AsNumbersTable
headers={[t('html.label.last30days'), t('html.label.last7days'), t('html.label.last24hours')]}
>
<TableRow icon={faExclamationCircle} color="red" text={t('html.label.lowTpsSpikes')}
values={[
data.low_tps_spikes_30d,
data.low_tps_spikes_7d,
data.low_tps_spikes_24h
]}/>
<TableRow icon={faPowerOff} color="red"
text={t('html.label.serverDowntime') + ' (' + t('generic.noData') + ')'}
values={[
data.server_downtime_30d,
data.server_downtime_7d,
data.server_downtime_24h
]}/>
<TableRow icon={faUser} color="light-blue" text={t('html.label.averagePlayers')}
values={[
data.players_30d,
data.players_7d,
data.players_24h
]}/>
<TableRow icon={faTachometerAlt} color="orange" text={t('html.label.averageTps')}
values={[
data.tps_30d,
data.tps_7d,
data.tps_24h
]}/>
<TableRow icon={faTachometerAlt} color="amber" text={t('html.label.averageCpuUsage')}
values={[
data.cpu_30d,
data.cpu_7d,
data.cpu_24h
]}/>
<TableRow icon={faMicrochip} color="light-green" text={t('html.label.averageRamUsage')}
values={[
data.ram_30d,
data.ram_7d,
data.ram_24h
]}/>
<TableRow icon={faDragon} color="purple" text={t('html.label.averageEntities')}
values={[
data.entities_30d,
data.entities_7d,
data.entities_24h
]}/>
<TableRow icon={faMap} color="blue-grey"
text={<>{t('html.label.averageChunks')}{' '}{data.chunks_30d === 'Unavailable' ?
<Fa icon={faEye} title={t('html.description.noSpongeChunks')}/> : ''}</>}
values={[
data.chunks_30d,
data.chunks_7d,
data.chunks_24h
]}/>
<TableRow icon={faHdd} color="green"
text={t('html.label.maxFreeDisk')}
values={[
data.max_disk_30d,
data.max_disk_7d,
data.max_disk_24h
]}/>
<TableRow icon={faHdd} color="green"
text={t('html.label.minFreeDisk')}
values={[
data.min_disk_30d,
data.min_disk_7d,
data.min_disk_24h
]}/>
</AsNumbersTable>
)
}
export default PerformanceAsNumbersTable;

View File

@ -36,6 +36,12 @@ export const fetchPvpPve = async (identifier) => {
return doGetRequest(url);
}
export const fetchPerformanceOverview = async (identifier) => {
const timestamp = Date.now();
const url = `/v1/performanceOverview?server=${identifier}&timestamp=${timestamp}`;
return doGetRequest(url);
}
export const fetchSessions = async (identifier) => {
const timestamp = Date.now();
const url = `/v1/sessions?server=${identifier}&timestamp=${timestamp}`;
@ -107,3 +113,9 @@ export const fetchGeolocations = async (identifier) => {
const url = `/v1/graph?type=geolocation&server=${identifier}&timestamp=${timestamp}`;
return doGetRequest(url);
}
export const fetchOptimizedPerformance = async (identifier) => {
const timestamp = Date.now();
const url = `/v1/graph?type=optimizedPerformance&server=${identifier}&timestamp=${timestamp}`;
return doGetRequest(url);
}

View File

@ -0,0 +1,40 @@
import React from 'react';
import LoadIn from "../../components/animation/LoadIn";
import {Col, Row} from "react-bootstrap-v5";
import {useParams} from "react-router-dom";
import {useDataRequest} from "../../hooks/dataFetchHook";
import {fetchPerformanceOverview} from "../../service/serverService";
import PerformanceGraphsCard from "../../components/cards/server/graphs/PerformanceGraphsCard";
import PerformanceInsightsCard from "../../components/cards/server/insights/PerformanceInsightsCard";
import {ErrorViewCard} from "../ErrorView";
import PerformanceAsNumbersCard from "../../components/cards/server/tables/PerformanceAsNumbersCard";
const ServerPerformance = () => {
const {identifier} = useParams();
const {data, loadingError} = useDataRequest(fetchPerformanceOverview, [identifier]);
return (
<LoadIn>
<section className="server_performance">
<Row>
<Col lg={12}>
<PerformanceGraphsCard/>
</Col>
</Row>
<Row>
<Col lg={8}>
{loadingError ? <ErrorViewCard error={loadingError}/> :
<PerformanceAsNumbersCard data={data?.numbers}/>}
</Col>
<Col lg={4}>
{loadingError ? <ErrorViewCard error={loadingError}/> :
<PerformanceInsightsCard data={data?.insights}/>}
</Col>
</Row>
</section>
</LoadIn>
)
};
export default ServerPerformance