mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2025-01-01 05:57:50 +01:00
Server Health Analysis #391
This commit is contained in:
parent
3222465f13
commit
d52de52cf0
@ -41,10 +41,13 @@ public class AnalysisData extends RawData {
|
|||||||
private long refreshDate;
|
private long refreshDate;
|
||||||
private String pluginsTabLayout;
|
private String pluginsTabLayout;
|
||||||
private Map<String, Serializable> additionalDataReplaceMap;
|
private Map<String, Serializable> additionalDataReplaceMap;
|
||||||
@Deprecated
|
|
||||||
private String playersTable;
|
private Map<String, Long> analyzedValues;
|
||||||
|
private Set<StickyData> stickyMonthData;
|
||||||
|
|
||||||
public AnalysisData() {
|
public AnalysisData() {
|
||||||
|
analyzedValues = new HashMap<>();
|
||||||
|
stickyMonthData = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPluginsTabLayout(String pluginsTabLayout) {
|
public void setPluginsTabLayout(String pluginsTabLayout) {
|
||||||
@ -55,10 +58,6 @@ public class AnalysisData extends RawData {
|
|||||||
this.additionalDataReplaceMap = additionalDataReplaceMap;
|
this.additionalDataReplaceMap = additionalDataReplaceMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPlayersTable(String playersTable) {
|
|
||||||
this.playersTable = playersTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addConstants() {
|
private void addConstants() {
|
||||||
addValue("version", MiscUtils.getIPlan().getVersion());
|
addValue("version", MiscUtils.getIPlan().getVersion());
|
||||||
addValue("worldPieColors", Settings.THEME_GRAPH_WORLD_PIE.toString());
|
addValue("worldPieColors", Settings.THEME_GRAPH_WORLD_PIE.toString());
|
||||||
@ -95,13 +94,18 @@ public class AnalysisData extends RawData {
|
|||||||
long weekAgo = now - TimeAmount.WEEK.ms();
|
long weekAgo = now - TimeAmount.WEEK.ms();
|
||||||
long monthAgo = now - TimeAmount.MONTH.ms();
|
long monthAgo = now - TimeAmount.MONTH.ms();
|
||||||
|
|
||||||
|
got("now", now);
|
||||||
|
got("dayAgo", dayAgo);
|
||||||
|
got("weekAgo", weekAgo);
|
||||||
|
got("monthAgo", monthAgo);
|
||||||
|
|
||||||
Map<UUID, List<Session>> sessions = profile.getSessions();
|
Map<UUID, List<Session>> sessions = profile.getSessions();
|
||||||
List<Session> allSessions = profile.getAllSessions();
|
List<Session> allSessions = profile.getAllSessions();
|
||||||
allSessions.sort(new SessionStartComparator());
|
allSessions.sort(new SessionStartComparator());
|
||||||
|
|
||||||
List<PlayerProfile> players = profile.getPlayers();
|
List<PlayerProfile> players = profile.getPlayers();
|
||||||
List<PlayerProfile> ops = profile.getOps().collect(Collectors.toList());
|
List<PlayerProfile> ops = profile.getOps().collect(Collectors.toList());
|
||||||
int playersTotal = players.size();
|
long playersTotal = got("playersTotal", players.size());
|
||||||
|
|
||||||
List<TPS> tpsData = profile.getTPSData(0, now).collect(Collectors.toList());
|
List<TPS> tpsData = profile.getTPSData(0, now).collect(Collectors.toList());
|
||||||
List<TPS> tpsDataDay = profile.getTPSData(dayAgo, now).collect(Collectors.toList());
|
List<TPS> tpsDataDay = profile.getTPSData(dayAgo, now).collect(Collectors.toList());
|
||||||
@ -121,16 +125,224 @@ public class AnalysisData extends RawData {
|
|||||||
addValue("ops", ops.size());
|
addValue("ops", ops.size());
|
||||||
addValue("playersTotal", playersTotal);
|
addValue("playersTotal", playersTotal);
|
||||||
|
|
||||||
|
healthTab(now, monthAgo, players, tpsDataMonth);
|
||||||
|
|
||||||
|
long totalPlaytime = profile.getTotalPlaytime();
|
||||||
|
addValue("playtimeTotal", playersTotal != 0 ? FormatUtils.formatTimeAmount(totalPlaytime) : "No Players");
|
||||||
|
addValue("playtimeAverage", playersTotal != 0 ? FormatUtils.formatTimeAmount(MathUtils.averageLong(totalPlaytime, playersTotal)) : "-");
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void healthTab(long now, long monthAgo, List<PlayerProfile> players, List<TPS> tpsDataMonth) {
|
||||||
|
double serverHealth = 100.0;
|
||||||
|
List<String> healthNotes = new ArrayList<>();
|
||||||
|
|
||||||
|
TreeMap<Long, Map<String, Set<UUID>>> activityData = new TreeMap<>();
|
||||||
|
for (PlayerProfile player : players) {
|
||||||
|
for (long date = now; date >= now - TimeAmount.MONTH.ms() * 2L; date -= TimeAmount.WEEK.ms() * 2L) {
|
||||||
|
double activityIndex = player.getActivityIndex(date);
|
||||||
|
String index = FormatUtils.readableActivityIndex(activityIndex)[1];
|
||||||
|
|
||||||
|
Map<String, Set<UUID>> map = activityData.getOrDefault(date, new HashMap<>());
|
||||||
|
Set<UUID> uuids = map.getOrDefault(index, new HashSet<>());
|
||||||
|
uuids.add(player.getUuid());
|
||||||
|
map.put(index, uuids);
|
||||||
|
activityData.put(date, map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long fourWeeksAgo = now - TimeAmount.WEEK.ms() * 4L;
|
||||||
|
|
||||||
|
Map<String, Set<UUID>> activityNow = activityData.get(now);
|
||||||
|
Map<String, Set<UUID>> activityFourWAgo = activityData.get(fourWeeksAgo);
|
||||||
|
|
||||||
|
Set<UUID> veryActiveNow = activityNow.getOrDefault("Very Active", new HashSet<>());
|
||||||
|
Set<UUID> activeNow = activityNow.getOrDefault("Active", new HashSet<>());
|
||||||
|
Set<UUID> regularNow = activityNow.getOrDefault("Regular", new HashSet<>());
|
||||||
|
Set<UUID> veryActiveFWAG = activityFourWAgo.getOrDefault("Very Active", new HashSet<>());
|
||||||
|
Set<UUID> activeFWAG = activityFourWAgo.getOrDefault("Active", new HashSet<>());
|
||||||
|
Set<UUID> regularFWAG = activityFourWAgo.getOrDefault("Regular", new HashSet<>());
|
||||||
|
|
||||||
|
Set<UUID> regularRemainCompareSet = new HashSet<>(regularFWAG);
|
||||||
|
regularRemainCompareSet.addAll(activeFWAG);
|
||||||
|
regularRemainCompareSet.addAll(veryActiveFWAG);
|
||||||
|
|
||||||
|
int activeFWAGNum = regularRemainCompareSet.size();
|
||||||
|
regularRemainCompareSet.removeAll(regularNow);
|
||||||
|
regularRemainCompareSet.removeAll(activeNow);
|
||||||
|
regularRemainCompareSet.removeAll(veryActiveNow);
|
||||||
|
int notRegularAnymore = regularRemainCompareSet.size();
|
||||||
|
int remain = activeFWAGNum - notRegularAnymore;
|
||||||
|
double percRemain = remain * 100.0 / activeFWAGNum;
|
||||||
|
|
||||||
|
Set<UUID> regularNewCompareSet = new HashSet<>(regularNow);
|
||||||
|
regularNewCompareSet.addAll(activeNow);
|
||||||
|
regularNewCompareSet.addAll(veryActiveNow);
|
||||||
|
regularNewCompareSet.removeAll(regularFWAG);
|
||||||
|
regularNewCompareSet.removeAll(activeFWAG);
|
||||||
|
regularNewCompareSet.removeAll(veryActiveFWAG);
|
||||||
|
int newActive = regularNewCompareSet.size();
|
||||||
|
|
||||||
|
int change = newActive - notRegularAnymore;
|
||||||
|
|
||||||
|
String remainNote = "";
|
||||||
|
if (activeFWAGNum != 0) {
|
||||||
|
remainNote = " ";
|
||||||
|
if (percRemain > 50) {
|
||||||
|
remainNote += Html.GREEN_THUMB.parse();
|
||||||
|
} else if (percRemain > 20) {
|
||||||
|
remainNote += Html.YELLOW_FLAG.parse();
|
||||||
|
} else {
|
||||||
|
remainNote += Html.RED_WARN.parse();
|
||||||
|
serverHealth -= 2.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
remainNote += " " + FormatUtils.cutDecimals(percRemain) + "% of regular players have remained active (" + remain + "/" + activeFWAGNum + ")";
|
||||||
|
}
|
||||||
|
if (change > 0) {
|
||||||
|
healthNotes.add(
|
||||||
|
"<p>" + Html.GREEN_THUMB.parse() + " Number of regular players has increased (+" + change + ")<br>" +
|
||||||
|
remainNote + "</p>");
|
||||||
|
} else if (change == 0) {
|
||||||
|
healthNotes.add(
|
||||||
|
"<p>" + Html.GREEN_THUMB.parse() + " Number of regular players has stayed the same (+" + change + ")<br>" +
|
||||||
|
remainNote + "</p>");
|
||||||
|
} else if (change > -20) {
|
||||||
|
healthNotes.add(
|
||||||
|
"<p>" + Html.YELLOW_FLAG.parse() + " Number of regular players has decreased (" + change + ")<br>" +
|
||||||
|
remainNote + "</p>");
|
||||||
|
serverHealth -= 5;
|
||||||
|
} else {
|
||||||
|
healthNotes.add(
|
||||||
|
"<p>" + Html.RED_WARN.parse() + " Number of regular players has decreased (" + change + ")<br>" +
|
||||||
|
remainNote + "</p>");
|
||||||
|
serverHealth -= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
double avgOnlineOnRegister = MathUtils.averageInt(stickyMonthData.stream().map(StickyData::getOnlineOnJoin));
|
||||||
|
if (avgOnlineOnRegister >= 1) {
|
||||||
|
healthNotes.add("<p>" + Html.GREEN_THUMB.parse() + " New Players have players to play with when they join ("
|
||||||
|
+ FormatUtils.cutDecimals(avgOnlineOnRegister) + " on average)</p>");
|
||||||
|
} else {
|
||||||
|
healthNotes.add("<p>" + Html.YELLOW_FLAG.parse() + " New Players may not have players to play with when they join ("
|
||||||
|
+ FormatUtils.cutDecimals(avgOnlineOnRegister) + " on average)</p>");
|
||||||
|
serverHealth -= 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
long newM = value("newM");
|
||||||
|
long stuckPerM = value("stuckPerM");
|
||||||
|
|
||||||
|
if (newM != 0) {
|
||||||
|
double stuckPerc = MathUtils.averageDouble(stuckPerM, newM) * 100;
|
||||||
|
if (stuckPerc >= 25) {
|
||||||
|
healthNotes.add("<p>" + Html.GREEN_THUMB.parse() + " " + FormatUtils.cutDecimals(stuckPerc)
|
||||||
|
+ "% of new players have stuck around (" + stuckPerM + "/" + newM + ")</p>");
|
||||||
|
} else {
|
||||||
|
healthNotes.add("<p>" + Html.YELLOW_FLAG.parse() + " " + FormatUtils.cutDecimals(stuckPerc)
|
||||||
|
+ "% of new players have stuck around (" + stuckPerM + "/" + newM + ")</p>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<PlayerProfile> currentActivePlayers = players.stream()
|
||||||
|
.filter(player -> player.getActivityIndex(now) >= 1.75)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
long twoWeeksAgo = now - TimeAmount.WEEK.ms() * 2L;
|
||||||
|
|
||||||
|
long totalFourToTwoWeeks = 0;
|
||||||
|
long totalLastTwoWeeks = 0;
|
||||||
|
for (PlayerProfile activePlayer : currentActivePlayers) {
|
||||||
|
totalFourToTwoWeeks += activePlayer.getPlaytime(monthAgo, twoWeeksAgo);
|
||||||
|
totalLastTwoWeeks += activePlayer.getPlaytime(twoWeeksAgo, now);
|
||||||
|
}
|
||||||
|
int currentlyActive = currentActivePlayers.size();
|
||||||
|
if (currentlyActive != 0) {
|
||||||
|
long avgFourToTwoWeeks = MathUtils.averageLong(totalFourToTwoWeeks, currentlyActive);
|
||||||
|
long avgLastTwoWeeks = MathUtils.averageLong(totalLastTwoWeeks, currentlyActive);
|
||||||
|
String avgLastTwoWeeksString = FormatUtils.formatTimeAmount(avgLastTwoWeeks);
|
||||||
|
String avgFourToTwoWeeksString = FormatUtils.formatTimeAmount(avgFourToTwoWeeks);
|
||||||
|
if (avgFourToTwoWeeks >= avgLastTwoWeeks) {
|
||||||
|
healthNotes.add("<p>" + Html.GREEN_THUMB.parse() + " Active players to have things to do ("
|
||||||
|
+ avgLastTwoWeeksString + " vs " + avgFourToTwoWeeksString
|
||||||
|
+ ")</p>");
|
||||||
|
} else if (avgFourToTwoWeeks - avgLastTwoWeeks > TimeAmount.HOUR.ms() * 2L) {
|
||||||
|
healthNotes.add("<p>" + Html.RED_WARN.parse() + " Active players might to be running out of things to do (Played "
|
||||||
|
+ avgLastTwoWeeksString + " vs " + avgFourToTwoWeeksString
|
||||||
|
+ ", last two weeks vs weeks 2-4)</p>");
|
||||||
|
serverHealth -= 5;
|
||||||
|
} else {
|
||||||
|
healthNotes.add("<p>" + Html.YELLOW_FLAG.parse() + " Active players might to be running out of things to do ("
|
||||||
|
+ avgLastTwoWeeksString + " vs " + avgFourToTwoWeeksString
|
||||||
|
+ ")</p>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long serverDownTime = ServerProfile.serverDownTime(tpsDataMonth);
|
||||||
|
long serverIdleTime = ServerProfile.serverIdleTime(tpsDataMonth);
|
||||||
|
double aboveThreshold = ServerProfile.aboveLowThreshold(tpsDataMonth);
|
||||||
|
long tpsSpikeMonth = value("tpsSpikeMonth");
|
||||||
|
|
||||||
|
String avgLowThresholdString = " ";
|
||||||
|
if (aboveThreshold >= 0.96) {
|
||||||
|
avgLowThresholdString += Html.GREEN_THUMB.parse();
|
||||||
|
} else if (aboveThreshold >= 0.9) {
|
||||||
|
avgLowThresholdString += Html.YELLOW_FLAG.parse();
|
||||||
|
serverHealth *= 0.9;
|
||||||
|
} else {
|
||||||
|
avgLowThresholdString += Html.RED_WARN.parse();
|
||||||
|
serverHealth *= 0.6;
|
||||||
|
}
|
||||||
|
avgLowThresholdString += " Average TPS was above Low Threshold "
|
||||||
|
+ FormatUtils.cutDecimals(aboveThreshold * 100.0) + "% of the time";
|
||||||
|
|
||||||
|
if (tpsSpikeMonth <= 5) {
|
||||||
|
healthNotes.add("<p>" + Html.GREEN_THUMB.parse()
|
||||||
|
+ " Average TPS dropped below Low Threshold (" + Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber() + ")" +
|
||||||
|
" " + tpsSpikeMonth + " times<br>" +
|
||||||
|
avgLowThresholdString + "</p>");
|
||||||
|
} else if (tpsSpikeMonth <= 25) {
|
||||||
|
healthNotes.add("<p>" + Html.YELLOW_FLAG.parse()
|
||||||
|
+ " Average TPS dropped below Low Threshold (" + Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber() + ")" +
|
||||||
|
" " + tpsSpikeMonth + " times<br>" +
|
||||||
|
avgLowThresholdString + "</p>");
|
||||||
|
serverHealth *= 0.95;
|
||||||
|
} else {
|
||||||
|
healthNotes.add("<p>" + Html.RED_WARN.parse()
|
||||||
|
+ " Average TPS dropped below Low Threshold (" + Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber() + ")" +
|
||||||
|
" " + tpsSpikeMonth + " times<br>" +
|
||||||
|
avgLowThresholdString + "</p>");
|
||||||
|
serverHealth *= 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverDownTime <= TimeAmount.DAY.ms()) {
|
||||||
|
healthNotes.add("<p>" + Html.GREEN_THUMB.parse() + " Total Server downtime (No Data) was "
|
||||||
|
+ FormatUtils.formatTimeAmount(serverDownTime) + "</p>");
|
||||||
|
} else if (serverDownTime <= TimeAmount.WEEK.ms()) {
|
||||||
|
healthNotes.add("<p>" + Html.YELLOW_FLAG.parse() + " Total Server downtime (No Data) was "
|
||||||
|
+ FormatUtils.formatTimeAmount(serverDownTime) + "</p>");
|
||||||
|
serverHealth *= 0.6;
|
||||||
|
} else {
|
||||||
|
healthNotes.add("<p>" + Html.RED_WARN.parse() + " Total Server downtime (No Data) was "
|
||||||
|
+ FormatUtils.formatTimeAmount(serverDownTime) + "</p>");
|
||||||
|
serverHealth *= 0.3;
|
||||||
|
}
|
||||||
|
healthNotes.add("<p>" + Html.FA_COLORED_ICON.parse("red", "life-ring") + " Server was idle (No Players) "
|
||||||
|
+ FormatUtils.formatTimeAmount(serverIdleTime) + "</p>");
|
||||||
|
|
||||||
|
StringBuilder healthNoteBuilder = new StringBuilder();
|
||||||
|
for (String healthNote : healthNotes) {
|
||||||
|
healthNoteBuilder.append(healthNote);
|
||||||
|
}
|
||||||
|
addValue("healthNotes", healthNoteBuilder.toString());
|
||||||
|
addValue("healthIndex", serverHealth);
|
||||||
|
|
||||||
// TODO Rewrite Activity Pie
|
// TODO Rewrite Activity Pie
|
||||||
addValue("playersActive", 0);
|
addValue("playersActive", 0);
|
||||||
addValue("active", 0);
|
addValue("active", 0);
|
||||||
addValue("inactive", 0);
|
addValue("inactive", 0);
|
||||||
addValue("joinLeaver", 0);
|
addValue("joinLeaver", 0);
|
||||||
addValue("banned", 0);
|
addValue("banned", 0);
|
||||||
|
|
||||||
long totalPlaytime = profile.getTotalPlaytime();
|
|
||||||
addValue("playtimeTotal", playersTotal != 0 ? FormatUtils.formatTimeAmount(totalPlaytime) : "No Players");
|
|
||||||
addValue("playtimeAverage", playersTotal != 0 ? FormatUtils.formatTimeAmount(MathUtils.averageLong(totalPlaytime, playersTotal)) : "-");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void commandUsage(Map<String, Integer> commandUsage) {
|
private void commandUsage(Map<String, Integer> commandUsage) {
|
||||||
@ -144,10 +356,10 @@ public class AnalysisData extends RawData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onlineActivityNumbers(ServerProfile profile, Map<UUID, List<Session>> sessions, List<PlayerProfile> players) {
|
private void onlineActivityNumbers(ServerProfile profile, Map<UUID, List<Session>> sessions, List<PlayerProfile> players) {
|
||||||
long now = MiscUtils.getTime();
|
long now = value("now");
|
||||||
long dayAgo = now - TimeAmount.DAY.ms();
|
long dayAgo = value("dayAgo");
|
||||||
long weekAgo = now - TimeAmount.WEEK.ms();
|
long weekAgo = value("weekAgo");
|
||||||
long monthAgo = now - TimeAmount.MONTH.ms();
|
long monthAgo = value("monthAgo");
|
||||||
|
|
||||||
List<PlayerProfile> newDay = profile.getPlayersWhoRegistered(dayAgo, now).collect(Collectors.toList());
|
List<PlayerProfile> newDay = profile.getPlayersWhoRegistered(dayAgo, now).collect(Collectors.toList());
|
||||||
List<PlayerProfile> newWeek = profile.getPlayersWhoRegistered(weekAgo, now).collect(Collectors.toList());
|
List<PlayerProfile> newWeek = profile.getPlayersWhoRegistered(weekAgo, now).collect(Collectors.toList());
|
||||||
@ -159,10 +371,10 @@ public class AnalysisData extends RawData {
|
|||||||
int uniqD = uniqueDay.size();
|
int uniqD = uniqueDay.size();
|
||||||
int uniqW = uniqueWeek.size();
|
int uniqW = uniqueWeek.size();
|
||||||
int uniqM = uniqueMonth.size();
|
int uniqM = uniqueMonth.size();
|
||||||
int newD = newDay.size();
|
long newD = got("newD", newDay.size());
|
||||||
int newW = newWeek.size();
|
long newW = got("newW", newWeek.size());
|
||||||
int newM = newMonth.size();
|
long newM = got("newM", newMonth.size());
|
||||||
int playersTotal = players.size();
|
long playersTotal = value("playersTotal");
|
||||||
|
|
||||||
addValue("playersDay", uniqD);
|
addValue("playersDay", uniqD);
|
||||||
addValue("playersWeek", uniqW);
|
addValue("playersWeek", uniqW);
|
||||||
@ -180,12 +392,15 @@ public class AnalysisData extends RawData {
|
|||||||
addValue("playersNewAverageWeek", AnalysisUtils.getNewUsersPerDay(toRegistered(newWeek), -1, newW));
|
addValue("playersNewAverageWeek", AnalysisUtils.getNewUsersPerDay(toRegistered(newWeek), -1, newW));
|
||||||
addValue("playersNewAverageMonth", AnalysisUtils.getNewUsersPerDay(toRegistered(newMonth), -1, newM));
|
addValue("playersNewAverageMonth", AnalysisUtils.getNewUsersPerDay(toRegistered(newMonth), -1, newM));
|
||||||
|
|
||||||
stickiness(now, weekAgo, monthAgo, newDay, newWeek, newMonth, newD, newW, newM);
|
stickiness(now, weekAgo, monthAgo, newDay, newWeek, newMonth);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stickiness(long now, long weekAgo, long monthAgo,
|
private void stickiness(long now, long weekAgo, long monthAgo,
|
||||||
List<PlayerProfile> newDay, List<PlayerProfile> newWeek, List<PlayerProfile> newMonth,
|
List<PlayerProfile> newDay, List<PlayerProfile> newWeek, List<PlayerProfile> newMonth) {
|
||||||
int newD, int newW, int newM) {
|
long newD = value("newD");
|
||||||
|
long newW = value("newW");
|
||||||
|
long newM = value("newM");
|
||||||
|
|
||||||
long fourDaysAgo = now - TimeAmount.DAY.ms() * 4L;
|
long fourDaysAgo = now - TimeAmount.DAY.ms() * 4L;
|
||||||
long twoWeeksAgo = now - TimeAmount.WEEK.ms() * 2L;
|
long twoWeeksAgo = now - TimeAmount.WEEK.ms() * 2L;
|
||||||
|
|
||||||
@ -198,6 +413,8 @@ public class AnalysisData extends RawData {
|
|||||||
|
|
||||||
int stuckPerM = playersStuckPerMonth.size();
|
int stuckPerM = playersStuckPerMonth.size();
|
||||||
int stuckPerW = playersStuckPerWeek.size();
|
int stuckPerW = playersStuckPerWeek.size();
|
||||||
|
got("stuckPerM", stuckPerM);
|
||||||
|
got("stuckPerW", stuckPerW);
|
||||||
|
|
||||||
addValue("playersStuckMonth", stuckPerM);
|
addValue("playersStuckMonth", stuckPerM);
|
||||||
addValue("playersStuckWeek", stuckPerW);
|
addValue("playersStuckWeek", stuckPerW);
|
||||||
@ -206,7 +423,7 @@ public class AnalysisData extends RawData {
|
|||||||
|
|
||||||
if (newD != 0) {
|
if (newD != 0) {
|
||||||
// New Players
|
// New Players
|
||||||
Set<StickyData> stickyM = newMonth.stream().map(StickyData::new).distinct().collect(Collectors.toSet());
|
stickyMonthData = newMonth.stream().map(StickyData::new).distinct().collect(Collectors.toSet());
|
||||||
Set<StickyData> stickyW = playersStuckPerMonth.stream().map(StickyData::new).distinct().collect(Collectors.toSet());
|
Set<StickyData> stickyW = playersStuckPerMonth.stream().map(StickyData::new).distinct().collect(Collectors.toSet());
|
||||||
// New Players who stayed
|
// New Players who stayed
|
||||||
Set<StickyData> stickyStuckM = newMonth.stream().map(StickyData::new).distinct().collect(Collectors.toSet());
|
Set<StickyData> stickyStuckM = newMonth.stream().map(StickyData::new).distinct().collect(Collectors.toSet());
|
||||||
@ -218,7 +435,7 @@ public class AnalysisData extends RawData {
|
|||||||
|
|
||||||
Set<StickyData> similarM = new HashSet<>();
|
Set<StickyData> similarM = new HashSet<>();
|
||||||
Set<StickyData> similarW = new HashSet<>();
|
Set<StickyData> similarW = new HashSet<>();
|
||||||
for (StickyData stickyData : stickyM) {
|
for (StickyData stickyData : stickyMonthData) {
|
||||||
if (stickyData.distance(data) < 2.5) {
|
if (stickyData.distance(data) < 2.5) {
|
||||||
similarM.add(stickyData);
|
similarM.add(stickyData);
|
||||||
}
|
}
|
||||||
@ -302,9 +519,12 @@ public class AnalysisData extends RawData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void performanceTab(List<TPS> tpsData, List<TPS> tpsDataDay, List<TPS> tpsDataWeek, List<TPS> tpsDataMonth) {
|
private void performanceTab(List<TPS> tpsData, List<TPS> tpsDataDay, List<TPS> tpsDataWeek, List<TPS> tpsDataMonth) {
|
||||||
addValue("tpsSpikeMonth", ServerProfile.getLowSpikeCount(tpsDataMonth));
|
got("tpsSpikeMonth", ServerProfile.getLowSpikeCount(tpsDataMonth));
|
||||||
addValue("tpsSpikeWeek", ServerProfile.getLowSpikeCount(tpsDataWeek));
|
got("tpsSpikeWeek", ServerProfile.getLowSpikeCount(tpsDataWeek));
|
||||||
addValue("tpsSpikeDay", ServerProfile.getLowSpikeCount(tpsDataDay));
|
got("tpsSpikeDay", ServerProfile.getLowSpikeCount(tpsDataDay));
|
||||||
|
addValue("tpsSpikeMonth", value("tpsSpikeMonth"));
|
||||||
|
addValue("tpsSpikeWeek", value("tpsSpikeWeek"));
|
||||||
|
addValue("tpsSpikeDay", value("tpsSpikeDay"));
|
||||||
|
|
||||||
addValue("playersOnlineSeries", PlayerActivityGraphCreator.buildSeriesDataString(tpsData));
|
addValue("playersOnlineSeries", PlayerActivityGraphCreator.buildSeriesDataString(tpsData));
|
||||||
addValue("tpsSeries", TPSGraphCreator.buildSeriesDataString(tpsData));
|
addValue("tpsSeries", TPSGraphCreator.buildSeriesDataString(tpsData));
|
||||||
@ -337,6 +557,15 @@ public class AnalysisData extends RawData {
|
|||||||
addValue("chunkAverageWeek", FormatUtils.cutDecimals(MathUtils.averageInt(tpsDataWeek.stream().map(TPS::getChunksLoaded).filter(i -> i != 0))));
|
addValue("chunkAverageWeek", FormatUtils.cutDecimals(MathUtils.averageInt(tpsDataWeek.stream().map(TPS::getChunksLoaded).filter(i -> i != 0))));
|
||||||
addValue("chunkAverageDay", FormatUtils.cutDecimals(MathUtils.averageInt(tpsDataDay.stream().map(TPS::getChunksLoaded).filter(i -> i != 0))));
|
addValue("chunkAverageDay", FormatUtils.cutDecimals(MathUtils.averageInt(tpsDataDay.stream().map(TPS::getChunksLoaded).filter(i -> i != 0))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long got(String key, long v) {
|
||||||
|
analyzedValues.put(key, v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long value(String key) {
|
||||||
|
return analyzedValues.getOrDefault(key, 0L);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StickyData {
|
class StickyData {
|
||||||
@ -368,6 +597,12 @@ class StickyData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (messagesSent == null) {
|
||||||
|
messagesSent = 0;
|
||||||
|
}
|
||||||
|
if (onlineOnJoin == null) {
|
||||||
|
onlineOnJoin = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double distance(StickyData data) {
|
public double distance(StickyData data) {
|
||||||
@ -393,4 +628,8 @@ class StickyData {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hashCode(activityIndex, messagesSent, onlineOnJoin);
|
return Objects.hashCode(activityIndex, messagesSent, onlineOnJoin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getOnlineOnJoin() {
|
||||||
|
return onlineOnJoin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,7 +340,7 @@ public class ServerProfile {
|
|||||||
for (TPS tps : tpsData) {
|
for (TPS tps : tpsData) {
|
||||||
long date = tps.getDate();
|
long date = tps.getDate();
|
||||||
int players = tps.getPlayers();
|
int players = tps.getPlayers();
|
||||||
if (lastDate != -1) {
|
if (lastDate == -1) {
|
||||||
lastDate = date;
|
lastDate = date;
|
||||||
lastPlayers = players;
|
lastPlayers = players;
|
||||||
continue;
|
continue;
|
||||||
@ -357,4 +357,21 @@ public class ServerProfile {
|
|||||||
|
|
||||||
return idleTime;
|
return idleTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static double aboveLowThreshold(List<TPS> tpsData) {
|
||||||
|
if (tpsData.isEmpty()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int threshold = Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber();
|
||||||
|
|
||||||
|
long count = 0;
|
||||||
|
for (TPS tps : tpsData) {
|
||||||
|
if (tps.getTicksPerSecond() >= threshold) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count / tpsData.size();
|
||||||
|
}
|
||||||
}
|
}
|
@ -30,6 +30,9 @@ public enum Html {
|
|||||||
//
|
//
|
||||||
FONT_AWESOME_ICON("<i class=\"fa fa-${0}\"></i>"),
|
FONT_AWESOME_ICON("<i class=\"fa fa-${0}\"></i>"),
|
||||||
FA_COLORED_ICON("<i class=\"col-${0} fa fa-${1}\"></i>"),
|
FA_COLORED_ICON("<i class=\"col-${0} fa fa-${1}\"></i>"),
|
||||||
|
GREEN_THUMB("<i class=\"fa fa-thumbs-up g\"></i>"),
|
||||||
|
YELLOW_FLAG("<i class=\"fa fa-flag o\"></i>"),
|
||||||
|
RED_WARN("<i class=\"fa fa-exclamation-circle r\"></i>"),
|
||||||
SPAN("${0}</span>"),
|
SPAN("${0}</span>"),
|
||||||
BUTTON("<a class=\"button\" href=\"${0}\">${1}</a>"),
|
BUTTON("<a class=\"button\" href=\"${0}\">${1}</a>"),
|
||||||
BUTTON_CLASS("class=\"button\""),
|
BUTTON_CLASS("class=\"button\""),
|
||||||
|
@ -1,83 +1,101 @@
|
|||||||
function healthGauge(id, healthData) {
|
function healthGauge(id, healthData) {
|
||||||
var gaugeOptions = {
|
var gaugeOptions = {
|
||||||
|
|
||||||
chart: {
|
chart: {
|
||||||
type: 'solidgauge'
|
type: 'solidgauge'
|
||||||
},
|
|
||||||
|
|
||||||
title: null,
|
|
||||||
|
|
||||||
pane: {
|
|
||||||
center: ['50%', '85%'],
|
|
||||||
size: '140%',
|
|
||||||
startAngle: -90,
|
|
||||||
endAngle: 90,
|
|
||||||
background: {
|
|
||||||
backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || '#EEE',
|
|
||||||
innerRadius: '60%',
|
|
||||||
outerRadius: '100%',
|
|
||||||
shape: 'arc'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
tooltip: {
|
|
||||||
enabled: false
|
|
||||||
},
|
|
||||||
|
|
||||||
// the value axis
|
|
||||||
yAxis: {
|
|
||||||
stops: [
|
|
||||||
[0.1, '#DF5353'], // red
|
|
||||||
[0.5, '#DDDF0D'], // yellow
|
|
||||||
[0.9, '#55BF3B'] // green
|
|
||||||
],
|
|
||||||
lineWidth: 0,
|
|
||||||
minorTickInterval: null,
|
|
||||||
tickAmount: 2,
|
|
||||||
title: {
|
|
||||||
y: -70
|
|
||||||
},
|
},
|
||||||
labels: {
|
|
||||||
y: 16
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
plotOptions: {
|
title: null,
|
||||||
solidgauge: {
|
|
||||||
dataLabels: {
|
pane: {
|
||||||
y: 5,
|
center: ['50%', '85%'],
|
||||||
borderWidth: 0,
|
size: '140%',
|
||||||
useHTML: true
|
startAngle: -90,
|
||||||
|
endAngle: 90,
|
||||||
|
background: {
|
||||||
|
backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || '#EEE',
|
||||||
|
innerRadius: '60%',
|
||||||
|
outerRadius: '100%',
|
||||||
|
shape: 'arc'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
tooltip: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
|
||||||
|
// the value axis
|
||||||
|
yAxis: {
|
||||||
|
stops: [
|
||||||
|
[0.1, '#DF5353'], // red
|
||||||
|
[0.5, '#DDDF0D'], // yellow
|
||||||
|
[0.9, '#55BF3B'] // green
|
||||||
|
],
|
||||||
|
lineWidth: 0,
|
||||||
|
minorTickInterval: null,
|
||||||
|
tickAmount: 2,
|
||||||
|
title: {
|
||||||
|
y: -70
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
y: 16
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
plotOptions: {
|
||||||
|
solidgauge: {
|
||||||
|
dataLabels: {
|
||||||
|
y: 5,
|
||||||
|
borderWidth: 0,
|
||||||
|
useHTML: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
var chartSpeed = Highcharts.chart(id, Highcharts.merge(gaugeOptions, {
|
var chartSpeed = Highcharts.chart(id, Highcharts.merge(gaugeOptions, {
|
||||||
yAxis: {
|
yAxis: {
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 100,
|
max: 100,
|
||||||
title: {
|
title: {
|
||||||
text: 'Server Health'
|
text: 'Server Health'
|
||||||
|
},
|
||||||
|
visible: false
|
||||||
},
|
},
|
||||||
visible: false
|
|
||||||
},
|
|
||||||
|
|
||||||
credits: {
|
credits: {
|
||||||
enabled: false
|
enabled: false
|
||||||
},
|
},
|
||||||
|
|
||||||
series: [{
|
series: [{
|
||||||
name: 'health',
|
name: 'health',
|
||||||
data: healthData,
|
data: healthData,
|
||||||
dataLabels: {
|
dataLabels: {
|
||||||
formatter: function() {
|
formatter: function () {
|
||||||
return '<div style="text-align:center"><span style="font-size:25px;color:' +
|
return '<div style="text-align:center"><span style="font-size:25px;color:' +
|
||||||
((Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black') + '">'+(this.y).toFixed(2)+'</span><br/>' +
|
((Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black') + '">' + (this.y).toFixed(2) + '</span><br/>' +
|
||||||
'<span style="font-size:12px;color:silver">Very Healthy</span></div>';
|
'<span style="font-size:12px;color:silver">' + getLabel(this.y) + '</span></div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
|
|
||||||
}));
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLabel(index) {
|
||||||
|
if (index >= 80) {
|
||||||
|
return 'Very Healthy';
|
||||||
|
}
|
||||||
|
if (index >= 60) {
|
||||||
|
return 'Healthy';
|
||||||
|
}
|
||||||
|
if (index >= 50) {
|
||||||
|
return 'Good';
|
||||||
|
}
|
||||||
|
if (index >= 30) {
|
||||||
|
return 'OK';
|
||||||
|
}
|
||||||
|
if (index >= 0) {
|
||||||
|
return 'Poor';
|
||||||
|
}
|
||||||
}
|
}
|
@ -584,12 +584,12 @@
|
|||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="row clearfix">
|
<div class="row clearfix">
|
||||||
<div class="col-xs-12 col-sm-6">
|
<div class="col-xs-12 col-sm-6">
|
||||||
<h2><i class="col-red fa fa-life-ring"></i> Last 14 Days</h2>
|
<h2><i class="col-red fa fa-life-ring"></i> Last 30 Days</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="body bg-white">
|
<div class="body bg-white">
|
||||||
<p>${healthNotes} </p>
|
${healthNotes}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -934,6 +934,8 @@
|
|||||||
<script src="https://code.highcharts.com/maps/modules/map.js"></script>
|
<script src="https://code.highcharts.com/maps/modules/map.js"></script>
|
||||||
<script src="https://code.highcharts.com/mapdata/custom/world.js"></script>
|
<script src="https://code.highcharts.com/mapdata/custom/world.js"></script>
|
||||||
<script src="https://code.highcharts.com/modules/drilldown.js"></script>
|
<script src="https://code.highcharts.com/modules/drilldown.js"></script>
|
||||||
|
<script src="https://code.highcharts.com/highcharts-more.js"></script>
|
||||||
|
<script src="https://code.highcharts.com/modules/solid-gauge.js"></script>
|
||||||
<script src="https://code.highcharts.com/modules/no-data-to-display.js"></script>
|
<script src="https://code.highcharts.com/modules/no-data-to-display.js"></script>
|
||||||
|
|
||||||
<!-- Font Awesome -->
|
<!-- Font Awesome -->
|
||||||
@ -1103,6 +1105,7 @@
|
|||||||
worldChart('worldGraph', entitySeries, chunkSeries, playersOnlineSeries);
|
worldChart('worldGraph', entitySeries, chunkSeries, playersOnlineSeries);
|
||||||
worldMap('worldMap', '#EEFFEE', '#267f00', mapSeries);
|
worldMap('worldMap', '#EEFFEE', '#267f00', mapSeries);
|
||||||
punchCard('punchCard', punchcardSeries);
|
punchCard('punchCard', punchcardSeries);
|
||||||
|
healthGauge('healthGauge', [${healthIndex}]);
|
||||||
${sessionTabGraphViewFunctions}
|
${sessionTabGraphViewFunctions}
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
Reference in New Issue
Block a user