diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/Main.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/Main.java index 94e38b9..6d3034a 100644 --- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/Main.java +++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/Main.java @@ -68,8 +68,4 @@ public class Main extends JavaPlugin { } this.getLogger().info("Disabled PlayerStats!"); } - - public void logTimeTaken(String className, String methodName, long previousTime) { - getLogger().info(className + ", " + methodName + ": " + (System.currentTimeMillis() - previousTime) + "ms"); - } } diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/ThreadManager.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/ThreadManager.java index 9e11a93..412ea9e 100644 --- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/ThreadManager.java +++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/ThreadManager.java @@ -5,13 +5,16 @@ import com.gmail.artemis.the.gr8.playerstats.reload.ReloadThread; import com.gmail.artemis.the.gr8.playerstats.statistic.StatRequest; import com.gmail.artemis.the.gr8.playerstats.statistic.StatThread; import com.gmail.artemis.the.gr8.playerstats.msg.MessageFactory; +import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger; import net.kyori.adventure.platform.bukkit.BukkitAudiences; import org.bukkit.command.CommandSender; public class ThreadManager { - private static final int threshold = 10; + private final int threshold = 10; + private int statThreadID; + private int reloadThreadID; private final Main plugin; private final BukkitAudiences adventure; @@ -28,16 +31,27 @@ public class ThreadManager { messageFactory = m; plugin = p; - startReloadThread(null, true); + statThreadID = 0; + reloadThreadID = 0; + startReloadThread(null); } - public void startReloadThread(CommandSender sender, boolean firstTimeLoading) { - reloadThread = new ReloadThread(adventure, config, messageFactory, plugin, threshold, firstTimeLoading, statThread, sender); - reloadThread.start(); + public void startReloadThread(CommandSender sender) { + if (reloadThread == null || !reloadThread.isAlive()) { + reloadThreadID += 1; + + reloadThread = new ReloadThread(adventure, config, messageFactory, plugin, threshold, reloadThreadID, statThread, sender); + reloadThread.start(); + } + else { + MyLogger.threadAlreadyRunning(reloadThread.getName()); + } } public void startStatThread(StatRequest request) { - statThread = new StatThread(adventure, config, messageFactory, plugin, threshold, request, reloadThread); + statThreadID += 1; + + statThread = new StatThread(adventure, config, messageFactory, plugin, statThreadID, threshold, request, reloadThread); statThread.start(); } diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/ReloadCommand.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/ReloadCommand.java index 95d12e3..ea19f77 100644 --- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/ReloadCommand.java +++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/ReloadCommand.java @@ -17,7 +17,7 @@ public class ReloadCommand implements CommandExecutor { @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { - threadManager.startReloadThread(sender, false); + threadManager.startReloadThread(sender); return true; } } diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/StatCommand.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/StatCommand.java index 9f9d170..9f15e07 100644 --- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/StatCommand.java +++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/StatCommand.java @@ -169,7 +169,7 @@ public class StatCommand implements CommandExecutor { request.setPlayerName(sender.getName()); request.setSelection(Query.PLAYER); } - else if (OfflinePlayerHandler.isOfflinePlayerName(arg) && request.getPlayerName() == null) { + else if (OfflinePlayerHandler.isRelevantPlayer(arg) && request.getPlayerName() == null) { request.setPlayerName(arg); request.setSelection(Query.PLAYER); } diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/config/ConfigHandler.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/config/ConfigHandler.java index 47f9603..780cc64 100644 --- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/config/ConfigHandler.java +++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/config/ConfigHandler.java @@ -2,6 +2,7 @@ package com.gmail.artemis.the.gr8.playerstats.config; import com.gmail.artemis.the.gr8.playerstats.Main; import com.gmail.artemis.the.gr8.playerstats.enums.Query; +import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; @@ -24,15 +25,27 @@ public class ConfigHandler { configVersion = 3.1; checkConfigVersion(); + MyLogger.setDebugLevel(debugLevel()); } - /** Reloads the config from file, or creates a new file with default values if there is none. */ + /** Returns the desired debugging level. +

1 = low (only show unexpected errors)

+

2 = medium (show all encountered exceptions, log main tasks and show time taken)

+

3 = high (log all tasks and time taken)

+

Default: 1

*/ + public int debugLevel() { + return config.getInt("debug-level", 1); + } + + /** Reloads the config from file, or creates a new file with default values if there is none. + Also reads the value for debug-level and passes it on to MyLogger. */ public boolean reloadConfig() { try { if (!configFile.exists()) { saveDefaultConfig(); } config = YamlConfiguration.loadConfiguration(configFile); + MyLogger.setDebugLevel(debugLevel()); return true; } catch (Exception e) { diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/enums/DebugLevel.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/enums/DebugLevel.java new file mode 100644 index 0000000..3969097 --- /dev/null +++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/enums/DebugLevel.java @@ -0,0 +1,5 @@ +package com.gmail.artemis.the.gr8.playerstats.enums; + +public enum DebugLevel { + LOW, MEDIUM, HIGH +} diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/listeners/JoinListener.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/listeners/JoinListener.java index 1dd19bc..e6dfd6b 100644 --- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/listeners/JoinListener.java +++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/listeners/JoinListener.java @@ -16,7 +16,7 @@ public class JoinListener implements Listener { @EventHandler public void onPlayerJoin(PlayerJoinEvent joinEvent) { if (!joinEvent.getPlayer().hasPlayedBefore()) { - threadManager.startReloadThread(null, false); + threadManager.startReloadThread(null); } } } diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/reload/ReloadAction.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/reload/ReloadAction.java index 1088fa5..8b3af9b 100644 --- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/reload/ReloadAction.java +++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/reload/ReloadAction.java @@ -1,5 +1,6 @@ package com.gmail.artemis.the.gr8.playerstats.reload; +import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger; import com.gmail.artemis.the.gr8.playerstats.utils.UnixTimeHandler; import org.bukkit.OfflinePlayer; @@ -15,40 +16,33 @@ public class ReloadAction extends RecursiveAction { private final int start; private final int end; - private final boolean whitelistOnly; - private final boolean excludeBanned; private final int lastPlayedLimit; private final ConcurrentHashMap offlinePlayerUUIDs; /** Fills a ConcurrentHashMap with PlayerNames and UUIDs for all OfflinePlayers that should be included in statistic calculations. * @param threshold the maximum length of OfflinePlayers to process in one task * @param players array of all OfflinePlayers (straight from Bukkit) - * @param whitelistOnly whether to limit players based on the whitelist - * @param excludeBanned whether to exclude banned players * @param lastPlayedLimit whether to set a limit based on last-played-date * @param offlinePlayerUUIDs the ConcurrentHashMap to put resulting playerNames and UUIDs on */ public ReloadAction(int threshold, OfflinePlayer[] players, - boolean whitelistOnly, boolean excludeBanned, int lastPlayedLimit, - ConcurrentHashMap offlinePlayerUUIDs) { + int lastPlayedLimit, ConcurrentHashMap offlinePlayerUUIDs) { - this(threshold, players, 0, players.length, - whitelistOnly, excludeBanned, lastPlayedLimit, offlinePlayerUUIDs); + this(threshold, players, 0, players.length, lastPlayedLimit, offlinePlayerUUIDs); } protected ReloadAction(int threshold, OfflinePlayer[] players, int start, int end, - boolean whitelistOnly, boolean excludeBanned, int lastPlayedLimit, - ConcurrentHashMap offlinePlayerUUIDs) { + int lastPlayedLimit, ConcurrentHashMap offlinePlayerUUIDs) { this.threshold = threshold; this.players = players; this.start = start; this.end = end; - this.whitelistOnly = whitelistOnly; - this.excludeBanned = excludeBanned; this.lastPlayedLimit = lastPlayedLimit; this.offlinePlayerUUIDs = offlinePlayerUUIDs; + + MyLogger.subActionCreated(Thread.currentThread().getName()); } @Override @@ -60,9 +54,9 @@ public class ReloadAction extends RecursiveAction { else { final int split = length / 2; final ReloadAction subTask1 = new ReloadAction(threshold, players, start, (start + split), - whitelistOnly, excludeBanned, lastPlayedLimit, offlinePlayerUUIDs); + lastPlayedLimit, offlinePlayerUUIDs); final ReloadAction subTask2 = new ReloadAction(threshold, players, (start + split), end, - whitelistOnly, excludeBanned, lastPlayedLimit, offlinePlayerUUIDs); + lastPlayedLimit, offlinePlayerUUIDs); //queue and compute all subtasks in the right order invokeAll(subTask1, subTask2); @@ -72,11 +66,11 @@ public class ReloadAction extends RecursiveAction { private void process() { for (int i = start; i < end; i++) { OfflinePlayer player = players[i]; - if (player.getName() != null && - (!whitelistOnly || player.isWhitelisted()) && - (!excludeBanned || !player.isBanned()) && + String playerName = player.getName(); + MyLogger.actionRunning(Thread.currentThread().getName(), playerName, 1); + if (playerName != null && (lastPlayedLimit == 0 || UnixTimeHandler.hasPlayedSince(lastPlayedLimit, player.getLastPlayed()))) { - offlinePlayerUUIDs.put(player.getName(), player.getUniqueId()); + offlinePlayerUUIDs.put(playerName, player.getUniqueId()); } } } diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/reload/ReloadThread.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/reload/ReloadThread.java index aa707e6..b8d4a54 100644 --- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/reload/ReloadThread.java +++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/reload/ReloadThread.java @@ -5,6 +5,7 @@ import com.gmail.artemis.the.gr8.playerstats.ThreadManager; import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler; import com.gmail.artemis.the.gr8.playerstats.statistic.StatThread; import com.gmail.artemis.the.gr8.playerstats.msg.MessageFactory; +import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger; import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler; import net.kyori.adventure.platform.bukkit.BukkitAudiences; import org.bukkit.Bukkit; @@ -13,7 +14,9 @@ import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; import java.util.ConcurrentModificationException; +import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ForkJoinPool; @@ -21,6 +24,7 @@ import java.util.concurrent.ForkJoinPool; public class ReloadThread extends Thread { private final int threshold; + private final int reloadThreadID; private final BukkitAudiences adventure; private static ConfigHandler config; @@ -29,10 +33,11 @@ public class ReloadThread extends Thread { private final StatThread statThread; private final CommandSender sender; - private final boolean firstTimeLoading; - public ReloadThread(BukkitAudiences a, ConfigHandler c, MessageFactory m, Main p, int threshold, boolean firstTime, @Nullable StatThread s, @Nullable CommandSender se) { + public ReloadThread(BukkitAudiences a, ConfigHandler c, MessageFactory m, Main p, int threshold, int ID, @Nullable StatThread s, @Nullable CommandSender se) { this.threshold = threshold; + reloadThreadID = ID; + adventure = a; config = c; messageFactory = m; @@ -40,18 +45,21 @@ public class ReloadThread extends Thread { statThread = s; sender = se; - firstTimeLoading = firstTime; + + this.setName("ReloadThread-" + reloadThreadID); + MyLogger.threadCreated(this.getName()); } @Override public void run() { long time = System.currentTimeMillis(); + MyLogger.threadStart(this.getName()); - //if reload is triggered by /statreload... - if (!firstTimeLoading) { + //if reload is triggered by /statreload (aka this thread does not have ID number 1)... + if (reloadThreadID != 1) { if (statThread != null && statThread.isAlive()) { try { - plugin.getLogger().info("Waiting for statThread to finish up..."); + MyLogger.waitingForOtherThread(this.getName(), statThread.getName()); statThread.join(); } catch (InterruptedException e) { plugin.getLogger().warning(e.toString()); @@ -62,7 +70,7 @@ public class ReloadThread extends Thread { if (config.reloadConfig()) { try { - OfflinePlayerHandler.updateOfflinePlayerList(getPlayerMap(false)); + OfflinePlayerHandler.updateOfflinePlayerList(getPlayerMap()); } catch (ConcurrentModificationException e) { plugin.getLogger().warning("The request could not be fully executed due to a ConcurrentModificationException"); @@ -71,7 +79,7 @@ public class ReloadThread extends Thread { } } - plugin.logTimeTaken("ReloadThread", ("loaded " + OfflinePlayerHandler.getOfflinePlayerCount() + " offline players"), time); + MyLogger.logTimeTakenDefault("ReloadThread", ("loaded " + OfflinePlayerHandler.getOfflinePlayerCount() + " offline players"), time); if (sender != null) { adventure.sender(sender).sendMessage(messageFactory.reloadedConfig(sender instanceof ConsoleCommandSender)); } @@ -79,26 +87,36 @@ public class ReloadThread extends Thread { } //during first start-up... else { - OfflinePlayerHandler.updateOfflinePlayerList(getPlayerMap(true)); - plugin.logTimeTaken("ReloadThread", ("loaded " + OfflinePlayerHandler.getOfflinePlayerCount() + " offline players"), time); + OfflinePlayerHandler.updateOfflinePlayerList(getPlayerMap()); + MyLogger.logTimeTakenDefault("ReloadThread", ("loaded " + OfflinePlayerHandler.getOfflinePlayerCount() + " offline players"), time); ThreadManager.recordCalcTime(System.currentTimeMillis() - time); } } - private ConcurrentHashMap getPlayerMap(boolean firstTimeLoading) { - OfflinePlayer[] offlinePlayers = Bukkit.getOfflinePlayers(); - - int size; - if (firstTimeLoading) { - size = offlinePlayers.length; + private ConcurrentHashMap getPlayerMap() { + long time = System.currentTimeMillis(); + OfflinePlayer[] offlinePlayers; + if (config.whitelistOnly()) { + offlinePlayers = Bukkit.getWhitelistedPlayers().toArray(OfflinePlayer[]::new); + MyLogger.logTimeTaken("ReloadThread", "getting white-list-only list", time); + } + else if (config.excludeBanned()) { + Set bannedPlayers = Bukkit.getBannedPlayers(); + offlinePlayers = Arrays.stream(Bukkit.getOfflinePlayers()) + .parallel() + .filter(offlinePlayer -> !bannedPlayers.contains(offlinePlayer)).toArray(OfflinePlayer[]::new); + MyLogger.logTimeTaken("ReloadThread", "getting excluding-banned-players list", time); } else { - size = OfflinePlayerHandler.getOfflinePlayerCount() != 0 ? OfflinePlayerHandler.getOfflinePlayerCount() : 16; + offlinePlayers = Bukkit.getOfflinePlayers(); + MyLogger.logTimeTaken("ReloadThread", "getting regular player list", time); } + int size = offlinePlayers != null ? offlinePlayers.length : 16; ConcurrentHashMap playerMap = new ConcurrentHashMap<>(size); - ReloadAction task = new ReloadAction(threshold, offlinePlayers, config.whitelistOnly(), config.excludeBanned(), config.lastPlayedLimit(), playerMap); + ReloadAction task = new ReloadAction(threshold, offlinePlayers, config.lastPlayedLimit(), playerMap); + MyLogger.actionCreated((offlinePlayers != null) ? offlinePlayers.length : 0); ForkJoinPool commonPool = ForkJoinPool.commonPool(); try { @@ -106,6 +124,8 @@ public class ReloadThread extends Thread { } catch (ConcurrentModificationException e) { throw new ConcurrentModificationException(e.toString()); } + + MyLogger.actionFinished(1); return playerMap; } diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/statistic/StatThread.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/statistic/StatThread.java index c135eb5..9dfa703 100644 --- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/statistic/StatThread.java +++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/statistic/StatThread.java @@ -5,6 +5,7 @@ import com.gmail.artemis.the.gr8.playerstats.enums.Query; import com.gmail.artemis.the.gr8.playerstats.reload.ReloadThread; import com.gmail.artemis.the.gr8.playerstats.ThreadManager; import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler; +import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger; import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler; import com.gmail.artemis.the.gr8.playerstats.msg.MessageFactory; import com.google.common.collect.ImmutableList; @@ -23,6 +24,7 @@ import java.util.stream.Collectors; public class StatThread extends Thread { private final int threshold; + private final StatRequest request; private final ReloadThread reloadThread; @@ -32,8 +34,9 @@ public class StatThread extends Thread { private final Main plugin; //constructor (called on thread creation) - public StatThread(BukkitAudiences a, ConfigHandler c, MessageFactory m, Main p, int threshold, StatRequest s, @Nullable ReloadThread r) { + public StatThread(BukkitAudiences a, ConfigHandler c, MessageFactory m, Main p, int ID, int threshold, StatRequest s, @Nullable ReloadThread r) { this.threshold = threshold; + request = s; reloadThread = r; @@ -41,11 +44,16 @@ public class StatThread extends Thread { config = c; messageFactory = m; plugin = p; + + this.setName("StatThread-" + ID); + MyLogger.threadCreated(this.getName()); } //what the thread will do once started @Override public void run() throws IllegalStateException, NullPointerException { + MyLogger.threadStart(this.getName()); + if (messageFactory == null || plugin == null) { throw new IllegalStateException("Not all classes off the plugin are running!"); } @@ -54,8 +62,10 @@ public class StatThread extends Thread { } if (reloadThread != null && reloadThread.isAlive()) { try { - plugin.getLogger().info("Waiting for reloadThread to finish up..."); - adventure.sender(request.getCommandSender()).sendMessage(messageFactory.stillReloading(request.getCommandSender() instanceof ConsoleCommandSender)); + MyLogger.waitingForOtherThread(this.getName(), reloadThread.getName()); + adventure.sender(request.getCommandSender()) + .sendMessage(messageFactory + .stillReloading(request.getCommandSender() instanceof ConsoleCommandSender)); reloadThread.join(); } catch (InterruptedException e) { plugin.getLogger().warning(e.toString()); @@ -128,10 +138,11 @@ public class StatThread extends Thread { int size = OfflinePlayerHandler.getOfflinePlayerCount() != 0 ? (int) (OfflinePlayerHandler.getOfflinePlayerCount() * 1.05) : 16; ConcurrentHashMap playerStats = new ConcurrentHashMap<>(size); ImmutableList playerNames = ImmutableList.copyOf(OfflinePlayerHandler.getOfflinePlayerNames()); - TopStatAction task = new TopStatAction(threshold, playerNames, - request, playerStats); + TopStatAction task = new TopStatAction(threshold, playerNames, request, playerStats); + MyLogger.actionCreated(playerNames.size()); ForkJoinPool commonPool = ForkJoinPool.commonPool(); + try { commonPool.invoke(task); } catch (ConcurrentModificationException e) { @@ -140,8 +151,9 @@ public class StatThread extends Thread { throw new ConcurrentModificationException(e.toString()); } + MyLogger.actionFinished(2); ThreadManager.recordCalcTime(System.currentTimeMillis() - time); - plugin.logTimeTaken("StatThread", "calculated all stats", time); + MyLogger.logTimeTakenDefault("StatThread", "calculated all stats", time); return playerStats; } diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/statistic/TopStatAction.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/statistic/TopStatAction.java index 839c6a4..e80cc95 100644 --- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/statistic/TopStatAction.java +++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/statistic/TopStatAction.java @@ -1,5 +1,6 @@ package com.gmail.artemis.the.gr8.playerstats.statistic; +import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger; import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler; import com.google.common.collect.ImmutableList; import org.bukkit.OfflinePlayer; @@ -31,6 +32,8 @@ public class TopStatAction extends RecursiveAction { this.request = statRequest; this.playerStats = playerStats; + + MyLogger.subActionCreated(Thread.currentThread().getName()); } @Override @@ -53,6 +56,7 @@ public class TopStatAction extends RecursiveAction { if (iterator.hasNext()) { do { String playerName = iterator.next(); + MyLogger.actionRunning(Thread.currentThread().getName(), playerName, 2); OfflinePlayer player = OfflinePlayerHandler.getOfflinePlayer(playerName); if (player != null) { int statistic = 0; diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/MyLogger.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/MyLogger.java new file mode 100644 index 0000000..9ac4de5 --- /dev/null +++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/MyLogger.java @@ -0,0 +1,166 @@ +package com.gmail.artemis.the.gr8.playerstats.utils; + +import com.gmail.artemis.the.gr8.playerstats.enums.DebugLevel; +import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Logger; + +public class MyLogger { + + private static final Logger logger; + private static DebugLevel debugLevel; + + private static final String[] processedPlayers; + private static final AtomicInteger playersIndex; + private static ConcurrentHashMap threadNames; + + static{ + Plugin plugin = Bukkit.getPluginManager().getPlugin("PlayerStats"); + + logger = plugin != null ? plugin.getLogger() : Bukkit.getLogger(); + debugLevel = DebugLevel.LOW; + + processedPlayers = new String[10]; + playersIndex = new AtomicInteger(0); + threadNames = new ConcurrentHashMap<>(); + } + + private MyLogger() { + } + + /** Accesses the playersIndex to up it by 1 and return its previous value. */ + private static int nextPlayersIndex() { + return playersIndex.getAndIncrement(); + } + + /** Returns true if the playersIndex is 10, or any subsequent increment of 10. */ + private static boolean incrementOfTen() { + return (playersIndex.get() == 10 || (playersIndex.get() > 10 && playersIndex.get() % 10 == 0)); + } + + /** Sets the desired debugging level. +

1 = low (only show unexpected errors)

+

2 = medium (show all encountered exceptions, log main tasks and show time taken)

+

3 = high (log all tasks and time taken)

+

Default: 1

*/ + public static void setDebugLevel(int level) { + if (level == 2) { + debugLevel = DebugLevel.MEDIUM; + } + else if (level == 3) { + debugLevel = DebugLevel.HIGH; + } + else { + debugLevel = DebugLevel.LOW; + } + } + + /** Output to console that the given thread has been created (but not started yet).*/ + public static void threadCreated(String threadName) { + if (debugLevel != DebugLevel.LOW) { + logger.info(threadName + " created!"); + } + } + + /** Output to console that the given thread has been started. */ + public static void threadStart(String threadName) { + if (debugLevel == DebugLevel.MEDIUM || debugLevel == DebugLevel.HIGH) { + logger.info(threadName + " started!"); + } + } + + /** Output to console that another reloadThread is already running. */ + public static void threadAlreadyRunning(String threadName) { + logger.info("Another reloadThread is already running! (" + threadName + ")"); + } + + /** Output to console that the executingThread is waiting for otherThread to finish up. */ + public static void waitingForOtherThread(String executingThread, String otherThread) { + logger.info(executingThread + ": Waiting for " + otherThread + " to finish up..."); + } + + /** If DebugLevel is MEDIUM or HIGH, output to console that an action has started. + @param taskLength Length of the action (in terms of units-to-process)*/ + public static void actionCreated(int taskLength) { + if (debugLevel != DebugLevel.LOW) { + threadNames = new ConcurrentHashMap<>(); + playersIndex.set(0); + logger.info("Initial Action created for " + taskLength + " Players. Start Index is " + playersIndex.get() + ". Processing..."); + } + } + + /** Internally save the name of the executing thread for later logging of this action. + The list of names is reset upon the start of every new action. + @param threadName Name of the executing thread*/ + public static void subActionCreated(String threadName) { + if (debugLevel == DebugLevel.HIGH) { + if (!threadNames.containsKey(threadName)) { + threadNames.put(threadName, threadNames.size()); + } + } + } + + /** Internally save the name of the executing thread and processed player for logging, + and for the ReloadThread, if DebugLevel is HIGH, output the last 10 processed players once + there have been 10 names saved in MyLogger. This method is synchronized. + @param threadName Name of the executing thread + @param playerName Name of the player that was processed in this action + @param thread 1 for ReloadThread, 2 for StatThread */ + public static synchronized void actionRunning(String threadName, String playerName, int thread) { + if (debugLevel != DebugLevel.LOW) { + if (!threadNames.containsKey(threadName)) { + threadNames.put(threadName, threadNames.size()); + } + if (thread == 1 && debugLevel == DebugLevel.HIGH) { + if (incrementOfTen()) { + logger.info(Arrays.asList(processedPlayers).toString()); + } + processedPlayers[nextPlayersIndex() % 10] = playerName; + } + else if (debugLevel == DebugLevel.MEDIUM) { + nextPlayersIndex(); + } + } + } + + /** Output to console that an action has finished. +

For the ReloadThread, if DebugLevel is HIGH, output the left-over processed players. + For both threads, if DebugLevel is MEDIUM or HIGH, output the names of the threads that were used.

+ @param thread 1 for ReloadThread, 2 for StatThread */ + public static void actionFinished(int thread) { + if (thread == 1 && debugLevel == DebugLevel.HIGH) { + ArrayList leftOvers = new ArrayList<>(Arrays.asList(processedPlayers).subList(playersIndex.intValue() % 10, 10)); + logger.info(leftOvers.toString()); + } + if (debugLevel != DebugLevel.LOW) { + logger.info("Finished Recursive Action! In total " + + threadNames.size() + " Threads were used to process " + + playersIndex.get() + " Players: " + + Collections.list(threadNames.keys())); + } + } + + /** Output to console how long a certain task has taken if DebugLevel is MEDIUM or HIGH. + @param className Name of the class executing the task + @param methodName Name or description of the task + @param startTime Timestamp marking the beginning of the task */ + public static void logTimeTaken(String className, String methodName, long startTime) { + if (debugLevel != DebugLevel.LOW) { + logger.info(className + " " + methodName + ": " + (System.currentTimeMillis() - startTime) + "ms"); + } + } + + /** Output to console how long a certain task has taken (regardless of DebugLevel). + @param className Name of the class executing the task + @param methodName Name or description of the task + @param startTime Timestamp marking the beginning of the task */ + public static void logTimeTakenDefault(String className, String methodName, long startTime) { + logger.info(className + " " + methodName + ":" + (System.currentTimeMillis() - startTime) + "ms"); + } +} diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/OfflinePlayerHandler.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/OfflinePlayerHandler.java index 09a7748..168dc93 100644 --- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/OfflinePlayerHandler.java +++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/OfflinePlayerHandler.java @@ -12,18 +12,23 @@ public class OfflinePlayerHandler { private static ConcurrentHashMap offlinePlayerUUIDs; private static ArrayList playerNames; + static{ + offlinePlayerUUIDs = new ConcurrentHashMap<>(); + playerNames = new ArrayList<>(); + } + private OfflinePlayerHandler() { } /** Checks if a given playerName is on the private HashMap of players that should be included in statistic calculations @param playerName String, case-sensitive */ - public static boolean isOfflinePlayerName(String playerName) { + public static boolean isRelevantPlayer(String playerName) { return offlinePlayerUUIDs.containsKey(playerName); } /** Returns the number of OfflinePlayers that are included in statistic calculations */ public static int getOfflinePlayerCount() { - return offlinePlayerUUIDs != null ? offlinePlayerUUIDs.size() : 0; + return offlinePlayerUUIDs.size(); } /** Get an ArrayList of names from all OfflinePlayers that should be included in statistic calculations */ diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 4a4724d..6c88a0b 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -8,6 +8,12 @@ config-version: 3.1 # # General # # # # ------------------------------- # # +# How much output in console you'll get while PlayerStats is processing +# 1 = low (only show unexpected errors) +# 2 = medium (show all encountered exceptions, log main tasks and show time taken) +# 3 = high (log all tasks and time taken) +debug-level: 1 + # Filtering options to control which players should be included in statistic calculations include-whitelist-only: false exclude-banned-players: false