diff --git a/Plan/common/src/main/java/com/djrapitops/plan/data/store/mutators/TPSMutator.java b/Plan/common/src/main/java/com/djrapitops/plan/data/store/mutators/TPSMutator.java index 4325916c5..5331e6cee 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/data/store/mutators/TPSMutator.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/data/store/mutators/TPSMutator.java @@ -61,6 +61,10 @@ public class TPSMutator { return filterBy(tps -> tps.getDate() >= after && tps.getDate() <= before); } + public TPSMutator filterTPSBetween(int above, int below) { + return filterBy(tps -> tps.getTicksPerSecond() > above && tps.getTicksPerSecond() < below); + } + public List all() { return tpsData; } @@ -241,4 +245,10 @@ public class TPSMutator { .filter(num -> num >= 0) .min().orElse(-1); } + + public double averagePlayersOnline() { + return tpsData.stream() + .mapToDouble(TPS::getPlayers) + .average().orElse(-1); + } } \ No newline at end of file diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/json/PerformanceJSONParser.java b/Plan/common/src/main/java/com/djrapitops/plan/system/json/PerformanceJSONParser.java new file mode 100644 index 000000000..902868aae --- /dev/null +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/json/PerformanceJSONParser.java @@ -0,0 +1,146 @@ +/* + * This file is part of Player Analytics (Plan). + * + * Plan is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License v3 as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Plan is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Plan. If not, see . + */ +package com.djrapitops.plan.system.json; + +import com.djrapitops.plan.data.container.TPS; +import com.djrapitops.plan.data.store.mutators.TPSMutator; +import com.djrapitops.plan.db.Database; +import com.djrapitops.plan.db.access.queries.objects.TPSQueries; +import com.djrapitops.plan.system.database.DBSystem; +import com.djrapitops.plan.system.settings.config.PlanConfig; +import com.djrapitops.plan.system.settings.paths.DisplaySettings; +import com.djrapitops.plan.utilities.formatting.Formatter; +import com.djrapitops.plan.utilities.formatting.Formatters; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * Parses JSON payload for /server-page Performance tab. + * + * @author Rsl1122 + */ +@Singleton +public class PerformanceJSONParser implements TabJSONParser> { + + private final PlanConfig config; + private final DBSystem dbSystem; + + private final Formatter decimalFormatter; + private final Formatter timeAmountFormatter; + private final Formatter percentageFormatter; + + @Inject + public PerformanceJSONParser( + PlanConfig config, + DBSystem dbSystem, + Formatters formatters + ) { + this.config = config; + this.dbSystem = dbSystem; + + decimalFormatter = formatters.decimals(); + percentageFormatter = formatters.percentage(); + timeAmountFormatter = formatters.timeAmount(); + } + + public Map createJSONAsMap(UUID serverUUID) { + Map serverOverview = new HashMap<>(); + Database db = dbSystem.getDatabase(); + long now = System.currentTimeMillis(); + long monthAgo = now - TimeUnit.DAYS.toMillis(30L); + List tpsData = db.query(TPSQueries.fetchTPSDataOfServer(monthAgo, now, serverUUID)); + + serverOverview.put("numbers", createNumbersMap(tpsData)); + serverOverview.put("insights", createInsightsMap(tpsData, serverUUID)); + return serverOverview; + } + + private Map createNumbersMap(List tpsData) { + long now = System.currentTimeMillis(); + long dayAgo = now - TimeUnit.DAYS.toMillis(1L); + long weekAgo = now - TimeUnit.DAYS.toMillis(7L); + + Map numbers = new HashMap<>(); + + TPSMutator tpsDataMonth = new TPSMutator(tpsData); + TPSMutator tpsDataWeek = tpsDataMonth.filterDataBetween(weekAgo, now); + TPSMutator tpsDataDay = tpsDataWeek.filterDataBetween(dayAgo, now); + + Integer tpsThreshold = config.get(DisplaySettings.GRAPH_TPS_THRESHOLD_MED); + numbers.put("low_tps_spikes_30d", tpsDataMonth.lowTpsSpikeCount(tpsThreshold)); + numbers.put("low_tps_spikes_7d", tpsDataWeek.lowTpsSpikeCount(tpsThreshold)); + numbers.put("low_tps_spikes_24h", tpsDataDay.lowTpsSpikeCount(tpsThreshold)); + + numbers.put("server_downtime_30d", timeAmountFormatter.apply(tpsDataMonth.serverDownTime())); + numbers.put("server_downtime_7d", timeAmountFormatter.apply(tpsDataWeek.serverDownTime())); + numbers.put("server_downtime_24h", timeAmountFormatter.apply(tpsDataDay.serverDownTime())); + + numbers.put("tps_30d", format(tpsDataMonth.averageTPS())); + numbers.put("tps_7d", format(tpsDataWeek.averageTPS())); + numbers.put("tps_24h", format(tpsDataDay.averageTPS())); + numbers.put("cpu_30d", percentageFormatter.apply(tpsDataMonth.averageCPU() / 100.0)); + numbers.put("cpu_7d", percentageFormatter.apply(tpsDataWeek.averageCPU() / 100.0)); + numbers.put("cpu_24h", percentageFormatter.apply(tpsDataDay.averageCPU() / 100.0)); + numbers.put("ram_30d", format(tpsDataMonth.averageRAM()) + " MB"); + numbers.put("ram_7d", format(tpsDataWeek.averageRAM()) + " MB"); + numbers.put("ram_24h", format(tpsDataDay.averageRAM()) + " MB"); + numbers.put("entities_30d", (int) tpsDataMonth.averageEntities()); + numbers.put("entities_7d", (int) tpsDataWeek.averageEntities()); + numbers.put("entities_24h", (int) tpsDataDay.averageEntities()); + numbers.put("chunks_30d", (int) tpsDataMonth.averageChunks()); + numbers.put("chunks_7d", (int) tpsDataWeek.averageChunks()); + numbers.put("chunks_24h", (int) tpsDataDay.averageChunks()); + + numbers.put("max_disk_30d", tpsDataMonth.maxFreeDisk() + " Mb"); + numbers.put("max_disk_7d", tpsDataWeek.maxFreeDisk() + " Mb"); + numbers.put("max_disk_24h", tpsDataDay.maxFreeDisk() + " Mb"); + numbers.put("min_disk_30d", tpsDataMonth.minFreeDisk() + " Mb"); + numbers.put("min_disk_7d", tpsDataWeek.minFreeDisk() + " Mb"); + numbers.put("min_disk_24h", tpsDataDay.minFreeDisk() + " Mb"); + + return numbers; + } + + private String format(double value) { + return decimalFormatter.apply(value); + } + + private Map createInsightsMap(List tpsData, UUID serverUUID) { + Database db = dbSystem.getDatabase(); + long now = System.currentTimeMillis(); + long monthAgo = now - TimeUnit.DAYS.toMillis(30L); + + TPSMutator tpsMutator = new TPSMutator(tpsData); + Integer tpsThreshold = config.get(DisplaySettings.GRAPH_TPS_THRESHOLD_MED); + TPSMutator lowTPS = tpsMutator.filterTPSBetween(-1, tpsThreshold); + + Map insights = new HashMap<>(); + + insights.put("low_tps_players", decimalFormatter.apply(lowTPS.averagePlayersOnline())); + insights.put("low_tps_cpu", decimalFormatter.apply(lowTPS.averageCPU())); + insights.put("low_tps_entities", decimalFormatter.apply(lowTPS.averageEntities())); + insights.put("low_tps_chunks", decimalFormatter.apply(lowTPS.averageChunks())); + + insights.put("low_tps_disconnects", "Not implemented"); + insights.put("low_disk_space_dates", Collections.emptyList()); + + return insights; + } +} \ No newline at end of file diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/RootJSONHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/RootJSONHandler.java index ac48da58b..86c66fdfd 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/RootJSONHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/RootJSONHandler.java @@ -50,7 +50,8 @@ public class RootJSONHandler extends TreePageHandler { SessionsOverviewJSONParser sessionsOverviewJSONParser, PlayerKillsJSONHandler playerKillsJSONHandler, PvPPvEJSONParser pvPPvEJSONParser, - PlayerBaseOverviewJSONParser playerBaseOverviewJSONParser + PlayerBaseOverviewJSONParser playerBaseOverviewJSONParser, + PerformanceJSONParser performanceJSONParser ) { super(responseFactory); @@ -66,6 +67,7 @@ public class RootJSONHandler extends TreePageHandler { registerPage("sessionsOverview", sessionsOverviewJSONParser); registerPage("playerVersus", pvPPvEJSONParser); registerPage("playerbaseOverview", playerBaseOverviewJSONParser); + registerPage("performanceOverview", performanceJSONParser); } private void registerPage(String identifier, TabJSONParser tabJSONParser) { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/utilities/formatting/time/TimeAmountFormatter.java b/Plan/common/src/main/java/com/djrapitops/plan/utilities/formatting/time/TimeAmountFormatter.java index 1daeacc49..26c88659e 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/utilities/formatting/time/TimeAmountFormatter.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/utilities/formatting/time/TimeAmountFormatter.java @@ -45,7 +45,7 @@ public class TimeAmountFormatter implements Formatter { @Override public String apply(Long ms) { - if (ms <= 0) { + if (ms < 0) { return "-"; } StringBuilder builder = new StringBuilder(); @@ -107,20 +107,18 @@ public class TimeAmountFormatter implements Formatter { } private void appendSeconds(StringBuilder builder, long seconds, long minutes, long hours, String fHours, String fMinutes, String fSeconds) { - if (seconds != 0 || fSeconds.contains(ZERO_PH)) { - String s = fSeconds.replace(SECONDS_PH, String.valueOf(seconds)); - if (minutes == 0 && s.contains(MINUTES_PH)) { - if (hours == 0 && fMinutes.contains(HOURS_PH)) { - builder.append(fHours.replace(ZERO_PH, "0").replace(HOURS_PH, "0")); - } - builder.append(fMinutes.replace(HOURS_PH, "").replace(ZERO_PH, "0").replace(MINUTES_PH, "0")); + String s = fSeconds.replace(SECONDS_PH, String.valueOf(seconds)); + if (minutes == 0 && s.contains(MINUTES_PH)) { + if (hours == 0 && fMinutes.contains(HOURS_PH)) { + builder.append(fHours.replace(ZERO_PH, "0").replace(HOURS_PH, "0")); } - s = s.replace(MINUTES_PH, ""); - if (s.contains(ZERO_PH) && String.valueOf(seconds).length() == 1) { - builder.append('0'); - } - builder.append(s); + builder.append(fMinutes.replace(HOURS_PH, "").replace(ZERO_PH, "0").replace(MINUTES_PH, "0")); } + s = s.replace(MINUTES_PH, ""); + if (s.contains(ZERO_PH) && String.valueOf(seconds).length() == 1) { + builder.append('0'); + } + builder.append(s); } private void appendDays(StringBuilder builder, long days) { diff --git a/Plan/common/src/main/resources/assets/plan/web/server.html b/Plan/common/src/main/resources/assets/plan/web/server.html index 8ff3199a0..44561748c 100644 --- a/Plan/common/src/main/resources/assets/plan/web/server.html +++ b/Plan/common/src/main/resources/assets/plan/web/server.html @@ -1421,48 +1421,7 @@ jsonRequest("../v1/sessionsOverview?serverName=${serverName}", loadSessionValues); jsonRequest("../v1/playerVersus?serverName=${serverName}", loadPvPPvEValues); jsonRequest("../v1/playerbaseOverview?serverName=${serverName}", loadPlayerbaseOverviewValues); - loadPerformanceValues( - { - numbers: { - low_tps_spikes_30d: 4532, - low_tps_spikes_7d: 1235, - low_tps_spikes_24h: 411, - server_downtime_30d: '5d 1h 43m', - server_downtime_7d: '3d 1h 43m', - server_downtime_24h: '1h 43m', - tps_30d: '19.91', - tps_7d: '19.94', - tps_24h: '19.94', - cpu_30d: '16.91%', - cpu_7d: '14.4%', - cpu_24h: '16.01%', - ram_30d: '320 MB', - ram_7d: '432 MB', - ram_24h: '432 MB', - entities_30d: 43, - entities_7d: 26, - entities_24h: 75, - chunks_30d: 246, - chunks_7d: 256, - chunks_24h: 256, - max_disk_30d: '135113 Mb', - max_disk_7d: '134795 Mb', - max_disk_24h: '126425 Mb', - min_disk_30d: '79872 Mb', - min_disk_7d: '126419 Mb', - min_disk_24h: '126419 Mb' - }, - insights: { - low_tps_players: '32.54', - low_tps_entities: '432.54', - low_tps_disconnects: '6.43', - low_disk_space_dates: [ - '7 February 2019 12:34', - '8 February 2019 1:43' - ] - } - }, null - ); + jsonRequest("../v1/performanceOverview?serverName=${serverName}", loadPerformanceValues); setLoadingText('Rendering graphs..'); // TODO remove diff --git a/Plan/json-endpoints.md b/Plan/json-endpoints.md index 01590661b..e39816fb6 100644 --- a/Plan/json-endpoints.md +++ b/Plan/json-endpoints.md @@ -38,6 +38,8 @@ Parameter|Expected value|Description ### `GET /v1/players` +### `GET /v1/performanceOverview` + Obtain data for `/server` player list. Required parameters: `serverName` or `serverUUID`