diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/mutators/TPSMutator.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/mutators/TPSMutator.java index b2233c500..aa9ccf1b6 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/mutators/TPSMutator.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/mutators/TPSMutator.java @@ -249,4 +249,29 @@ public class TPSMutator { tpsData.sort(new TPSComparator()); return Optional.of(tpsData.get(tpsData.size() - 1)); } + + public Number[][] toArrays(boolean displayGaps) { + List arrays = new ArrayList<>(); + Long lastX = null; + for (TPS tps : tpsData) { + long date = tps.getDate(); + if (displayGaps && lastX != null && date - lastX > TimeUnit.MINUTES.toMillis(3L)) { + addMissingPoints(arrays, lastX, date); + } + lastX = date; + + arrays.add(tps.toArray()); + } + return arrays.toArray(new Number[0][]); + } + + private void addMissingPoints(List arrays, Long lastX, long date) { + long iterate = lastX + TimeUnit.MINUTES.toMillis(1L); + while (iterate < date) { + Number[] entry = new Number[7]; + entry[0] = iterate; + arrays.add(entry); + iterate += TimeUnit.MINUTES.toMillis(30L); + } + } } \ No newline at end of file diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/graphs/GraphJSONCreator.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/graphs/GraphJSONCreator.java index 20b8b6523..897fed9c8 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/graphs/GraphJSONCreator.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/graphs/GraphJSONCreator.java @@ -80,10 +80,7 @@ public class GraphJSONCreator { public String performanceGraphJSON(UUID serverUUID) { Database db = dbSystem.getDatabase(); LineGraphFactory lineGraphs = graphs.line(); - long now = System.currentTimeMillis(); - long halfYearAgo = now - TimeUnit.DAYS.toMillis(180L); - TPSMutator tpsMutator = new TPSMutator(db.query(TPSQueries.fetchTPSDataOfServer(serverUUID))) - .filterDataBetween(halfYearAgo, now); + TPSMutator tpsMutator = new TPSMutator(db.query(TPSQueries.fetchTPSDataOfServer(serverUUID))); return '{' + "\"playersOnline\":" + lineGraphs.playersOnlineGraph(tpsMutator).toHighChartsSeries() + ",\"tps\":" + lineGraphs.tpsGraph(tpsMutator).toHighChartsSeries() + @@ -109,6 +106,33 @@ public class GraphJSONCreator { "}}"; } + public Map optimizedPerformanceGraphJSON(UUID serverUUID) { + Database db = dbSystem.getDatabase(); + TPSMutator tpsMutator = new TPSMutator(db.query(TPSQueries.fetchTPSDataOfServer(serverUUID))); + Number[][] values = tpsMutator.toArrays(config.isTrue(DisplaySettings.GAPS_IN_GRAPH_DATA)); + + return Maps.builder(String.class, Object.class) + .put("keys", new String[]{"date", "playersOnline", "tps", "cpu", "ram", "entities", "chunks", "disk"}) + .put("values", values) + .put("colors", Maps.builder(String.class, Object.class) + .put("playersOnline", theme.getValue(ThemeVal.GRAPH_PLAYERS_ONLINE)) + .put("cpu", theme.getValue(ThemeVal.GRAPH_CPU)) + .put("ram", theme.getValue(ThemeVal.GRAPH_RAM)) + .put("entities", theme.getValue(ThemeVal.GRAPH_ENTITIES)) + .put("chunks", theme.getValue(ThemeVal.GRAPH_CHUNKS)) + .put("low", theme.getValue(ThemeVal.GRAPH_TPS_LOW)) + .put("med", theme.getValue(ThemeVal.GRAPH_TPS_MED)) + .put("high", theme.getValue(ThemeVal.GRAPH_TPS_HIGH)) + .build()) + .put("zones", Maps.builder(String.class, Object.class) + .put("tpsThresholdMed", config.get(DisplaySettings.GRAPH_TPS_THRESHOLD_MED)) + .put("tpsThresholdHigh", config.get(DisplaySettings.GRAPH_TPS_THRESHOLD_HIGH)) + .put("diskThresholdMed", config.get(DisplaySettings.GRAPH_DISK_THRESHOLD_MED)) + .put("diskThresholdHigh", config.get(DisplaySettings.GRAPH_DISK_THRESHOLD_HIGH)) + .build()) + .build(); + } + public String playersOnlineGraph(UUID serverUUID) { Database db = dbSystem.getDatabase(); long now = System.currentTimeMillis(); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/cache/DataID.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/cache/DataID.java index 17204653f..2900fee63 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/cache/DataID.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/cache/DataID.java @@ -30,6 +30,7 @@ public enum DataID { KILLS, PING_TABLE, GRAPH_PERFORMANCE, + GRAPH_OPTIMIZED_PERFORMANCE, GRAPH_ONLINE, GRAPH_UNIQUE_NEW, GRAPH_HOURLY_UNIQUE_NEW, diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/GraphsJSONResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/GraphsJSONResolver.java index cb78e4aea..ee2b6ec45 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/GraphsJSONResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/GraphsJSONResolver.java @@ -88,6 +88,8 @@ public class GraphsJSONResolver implements Resolver { switch (type) { case "performance": return DataID.GRAPH_PERFORMANCE; + case "optimizedPerformance": + return DataID.GRAPH_OPTIMIZED_PERFORMANCE; case "playersOnline": return DataID.GRAPH_ONLINE; case "uniqueAndNew": @@ -117,6 +119,8 @@ public class GraphsJSONResolver implements Resolver { switch (id) { case GRAPH_PERFORMANCE: return graphJSON.performanceGraphJSON(serverUUID); + case GRAPH_OPTIMIZED_PERFORMANCE: + return graphJSON.optimizedPerformanceGraphJSON(serverUUID); case GRAPH_ONLINE: return graphJSON.playersOnlineGraph(serverUUID); case GRAPH_UNIQUE_NEW: diff --git a/Plan/common/src/main/java/com/djrapitops/plan/gathering/domain/TPS.java b/Plan/common/src/main/java/com/djrapitops/plan/gathering/domain/TPS.java index c7bf0fa7a..eff1c5ffd 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/gathering/domain/TPS.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/gathering/domain/TPS.java @@ -168,4 +168,17 @@ public class TPS implements DateHolder { "chunksLoaded=" + chunksLoaded + ", " + "freeDiskSpace=" + freeDiskSpace + '}'; } + + public Number[] toArray() { + return new Number[]{ + getDate(), + getPlayers(), + getTicksPerSecond(), + getCPUUsage(), + getUsedMemory(), + getEntityCount(), + getChunksLoaded(), + getFreeDiskSpace() + }; + } } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/TPSQueries.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/TPSQueries.java index e80ce45fd..c20bd3339 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/TPSQueries.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/TPSQueries.java @@ -29,6 +29,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; +import java.util.concurrent.TimeUnit; import static com.djrapitops.plan.storage.database.sql.building.Sql.*; import static com.djrapitops.plan.storage.database.sql.tables.TPSTable.*; @@ -45,27 +46,72 @@ public class TPSQueries { } public static Query> fetchTPSDataOfServer(UUID serverUUID) { - String sql = Select.all(TABLE_NAME) - .where(SERVER_ID + "=" + ServerTable.STATEMENT_SELECT_SERVER_ID) - .toString(); + return db -> { + String selectLowestResolution = SELECT + + "MIN(t." + DATE + ") as " + DATE + ',' + + "MIN(t." + TPS + ") as " + TPS + ',' + + "MAX(t." + PLAYERS_ONLINE + ") as " + PLAYERS_ONLINE + ',' + + "MAX(t." + RAM_USAGE + ") as " + RAM_USAGE + ',' + + "MAX(t." + CPU_USAGE + ") as " + CPU_USAGE + ',' + + "MAX(t." + ENTITIES + ") as " + ENTITIES + ',' + + "MAX(t." + CHUNKS + ") as " + CHUNKS + ',' + + "MAX(t." + FREE_DISK + ") as " + FREE_DISK + + FROM + TABLE_NAME + " t" + + WHERE + SERVER_ID + "=" + ServerTable.STATEMENT_SELECT_SERVER_ID + + AND + DATE + "=?" + + AND + DATE + "=?"; - return new QueryStatement>(sql, 50000) { - @Override - public void prepare(PreparedStatement statement) throws SQLException { - statement.setString(1, serverUUID.toString()); - } + String sql = selectLowestResolution + + UNION + selectLowerResolution + + UNION + selectNormalResolution + + ORDER_BY + DATE; - @Override - public List processResults(ResultSet set) throws SQLException { - List data = new ArrayList<>(); - while (set.next()) { - - com.djrapitops.plan.gathering.domain.TPS tps = extractTPS(set); - - data.add(tps); + return db.query(new QueryStatement>(sql, 50000) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + long now = System.currentTimeMillis(); + long lowestResolution = TimeUnit.MINUTES.toMillis(20); + long lowResolution = TimeUnit.MINUTES.toMillis(5); + statement.setString(1, serverUUID.toString()); + statement.setLong(2, now - TimeUnit.DAYS.toMillis(60)); + statement.setLong(3, lowestResolution); + statement.setString(4, serverUUID.toString()); + statement.setLong(5, now - TimeUnit.DAYS.toMillis(60)); + statement.setLong(6, now - TimeUnit.DAYS.toMillis(30)); + statement.setLong(7, lowResolution); + statement.setString(8, serverUUID.toString()); + statement.setLong(9, now - TimeUnit.DAYS.toMillis(30)); } - return data; - } + + @Override + public List processResults(ResultSet set) throws SQLException { + List data = new ArrayList<>(); + while (set.next()) { + data.add(extractTPS(set)); + } + return data; + } + }); }; } diff --git a/Plan/common/src/main/resources/assets/plan/web/js/graphs.js b/Plan/common/src/main/resources/assets/plan/web/js/graphs.js index 106041d1f..c425f72b9 100644 --- a/Plan/common/src/main/resources/assets/plan/web/js/graphs.js +++ b/Plan/common/src/main/resources/assets/plan/web/js/graphs.js @@ -182,6 +182,29 @@ function onlineActivityCalendar(id, event_data, firstDay) { window.calendars.online_activity.render(); } +function mapToDataSeries(performanceData) { + const dataSeries = { + playersOnline: [], + tps: [], + cpu: [], + ram: [], + entities: [], + chunks: [], + disk: [] + }; + for (const entry of performanceData) { + const date = entry[0]; + dataSeries.playersOnline.push([date, entry[1]]); + dataSeries.tps.push([date, entry[2]]); + dataSeries.cpu.push([date, entry[3]]); + dataSeries.ram.push([date, entry[4]]); + dataSeries.entities.push([date, entry[5]]); + dataSeries.chunks.push([date, entry[6]]); + dataSeries.disk.push([date, entry[7]]); + } + return dataSeries; +} + function performanceChart(id, playersOnlineSeries, tpsSeries, cpuSeries, ramSeries, entitySeries, chunkSeries) { graphs.push(Highcharts.stockChart(id, { rangeSelector: { 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 b5541c75e..0eb39ef99 100644 --- a/Plan/common/src/main/resources/assets/plan/web/server.html +++ b/Plan/common/src/main/resources/assets/plan/web/server.html @@ -1330,9 +1330,9 @@ } }; - jsonRequest("../v1/graph?type=performance&server=${serverUUID}", function (json, error) { + jsonRequest("../v1/graph?type=optimizedPerformance&server=${serverUUID}", function (json, error) { if (json) { - var zones = { + const zones = { tps: [{ value: json.zones.tpsThresholdMed, color: json.colors.low @@ -1354,51 +1354,52 @@ color: json.colors.high }] }; - var series = { + const dataSeries = mapToDataSeries(json.values); + const series = { playersOnline: { name: s.name.playersOnline, type: s.type.areaSpline, tooltip: s.tooltip.zeroDecimals, - data: json.playersOnline, color: json.colors.playersOnline, yAxis: 0 + data: dataSeries.playersOnline, color: json.colors.playersOnline, yAxis: 0 }, tps: { name: s.name.tps, type: s.type.spline, color: json.colors.high, - zones: zones.tps, tooltip: s.tooltip.twoDecimals, data: json.tps, + zones: zones.tps, tooltip: s.tooltip.twoDecimals, data: dataSeries.tps, yAxis: 1 }, cpu: { name: s.name.cpu, type: s.type.spline, tooltip: s.tooltip.twoDecimals, - data: json.cpu, color: json.colors.cpu, yAxis: 2 + data: dataSeries.cpu, color: json.colors.cpu, yAxis: 2 }, cpu_alt: { name: s.name.cpu, type: s.type.spline, tooltip: s.tooltip.twoDecimals, - data: json.cpu, color: json.colors.cpu, yAxis: 1 + data: dataSeries.cpu, color: json.colors.cpu, yAxis: 1 }, ram: { name: s.name.ram, type: s.type.spline, tooltip: s.tooltip.zeroDecimals, - data: json.ram, color: json.colors.ram, yAxis: 3 + data: dataSeries.ram, color: json.colors.ram, yAxis: 3 }, ram_alt: { name: s.name.ram, type: s.type.spline, tooltip: s.tooltip.zeroDecimals, - data: json.ram, color: json.colors.ram, yAxis: 2 + data: dataSeries.ram, color: json.colors.ram, yAxis: 2 }, entities: { name: s.name.entities, type: s.type.spline, tooltip: s.tooltip.zeroDecimals, - data: json.entities, color: json.colors.entities, yAxis: 4 + data: dataSeries.entities, color: json.colors.entities, yAxis: 4 }, entities_alt: { name: s.name.entities, type: s.type.spline, tooltip: s.tooltip.zeroDecimals, - data: json.entities, color: json.colors.entities, yAxis: 1 + data: dataSeries.entities, color: json.colors.entities, yAxis: 1 }, chunks: { name: s.name.chunks, type: s.type.spline, tooltip: s.tooltip.zeroDecimals, - data: json.chunks, color: json.colors.chunks, yAxis: 5 + data: dataSeries.chunks, color: json.colors.chunks, yAxis: 5 }, chunks_alt: { name: s.name.chunks, type: s.type.spline, tooltip: s.tooltip.zeroDecimals, - data: json.chunks, color: json.colors.chunks, yAxis: 2 + data: dataSeries.chunks, color: json.colors.chunks, yAxis: 2 }, disk: { name: s.name.disk, type: s.type.spline, color: json.colors.high, - zones: zones.disk, tooltip: s.tooltip.zeroDecimals, data: json.disk + zones: zones.disk, tooltip: s.tooltip.zeroDecimals, data: dataSeries.disk } }; playersChart('playersOnlineChart', series.playersOnline, 2);