From 0e296b04dc926356a5905bdcd844c0f7cb07100c Mon Sep 17 00:00:00 2001 From: Keuin Date: Tue, 29 Dec 2020 15:15:46 +0800 Subject: 1.3.0: add `/blame stat` for showing statistics. --- src/main/java/com/keuin/blame/Blame.java | 11 ++- .../com/keuin/blame/command/BlameStatCommand.java | 109 +++++++++++++++++++++ .../blame/data/helper/VersionedLogEntryHelper.java | 22 +++++ 3 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/keuin/blame/command/BlameStatCommand.java create mode 100644 src/main/java/com/keuin/blame/data/helper/VersionedLogEntryHelper.java (limited to 'src/main/java/com/keuin/blame') diff --git a/src/main/java/com/keuin/blame/Blame.java b/src/main/java/com/keuin/blame/Blame.java index 2bf93ca..a4c806d 100644 --- a/src/main/java/com/keuin/blame/Blame.java +++ b/src/main/java/com/keuin/blame/Blame.java @@ -5,6 +5,7 @@ import com.keuin.blame.adapter.*; import com.keuin.blame.adapter.handler.PlaceBlockHandler; import com.keuin.blame.command.BlameBlockCommand; import com.keuin.blame.command.BlameLimitCommand; +import com.keuin.blame.command.BlameStatCommand; import com.keuin.blame.config.BlameConfig; import com.keuin.blame.lookup.LookupManager; import com.keuin.blame.util.DatabaseUtil; @@ -124,11 +125,17 @@ public class Blame implements ModInitializer { .then(CommandManager.argument("y", IntegerArgumentType.integer()) .then(CommandManager.argument("z", IntegerArgumentType.integer()) .then(CommandManager.argument("world", StringArgumentType.greedyString()) - .executes(BlameBlockCommand::blameGivenBlockPos))))))); + .executes(BlameBlockCommand::blameGivenBlockPos)))))) + ); commandDispatcher.register( CommandManager.literal("blame").then(CommandManager.literal("limit") .then(CommandManager.argument("limit", IntegerArgumentType.integer(1, 255)) - .executes(BlameLimitCommand::setLimit)))); + .executes(BlameLimitCommand::setLimit))) + ); + commandDispatcher.register( + CommandManager.literal("blame").then(CommandManager.literal("stat") + .executes(BlameStatCommand::showStat)) + ); } }); } diff --git a/src/main/java/com/keuin/blame/command/BlameStatCommand.java b/src/main/java/com/keuin/blame/command/BlameStatCommand.java new file mode 100644 index 0000000..677ea88 --- /dev/null +++ b/src/main/java/com/keuin/blame/command/BlameStatCommand.java @@ -0,0 +1,109 @@ +package com.keuin.blame.command; + +import com.keuin.blame.data.entry.LogEntry; +import com.keuin.blame.data.helper.VersionedLogEntryHelper; +import com.keuin.blame.util.DatabaseUtil; +import com.keuin.blame.util.PrintUtil; +import com.mojang.brigadier.context.CommandContext; +import com.mongodb.MongoClientException; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import net.minecraft.server.command.ServerCommandSource; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.logging.Logger; + +public class BlameStatCommand { + + private static final Logger logger = Logger.getLogger(BlameStatCommand.class.getName()); + + public static int showStat(CommandContext context) { + showStat(new ShowStatCallback() { + @Override + public void showStat(@Nullable BlameStat stat) { + StringBuilder sb = new StringBuilder(); + if (stat != null) { + sb.append("Data statistics\n"); + sb.append("===============\n"); + sb.append("\n"); + sb.append("# Count by subjects\n"); + stat.getCountMap().forEach((subjectId, count) -> { + sb.append(subjectId).append(": ").append(count).append("\n"); + }); + sb.append("\n"); + sb.append("=== END ===\n"); + } else { + sb.append("Failed to get statistics. Please refer to server log for more information.\n"); + } + PrintUtil.msgInfo(context, sb.toString()); + } + }); + return Commands.SUCCESS; + } + + public static void showStat(ShowStatCallback callback) { + Objects.requireNonNull(callback); + new Thread(new Runnable() { + @Override + public void run() { + logger.info("Collecting statistics..."); + try (final MongoClient mongoClient = MongoClients.create(DatabaseUtil.CLIENT_SETTINGS)) { + final MongoDatabase db = mongoClient.getDatabase( + DatabaseUtil.MONGO_CONFIG.getDatabaseName() + ); + final MongoCollection collection = db.getCollection( + DatabaseUtil.MONGO_CONFIG.getLogCollectionName(), LogEntry.class + ); + Collection ids = VersionedLogEntryHelper.getLoggedSubjectsId(collection); + + // count by distinct subjects + Map countMap = new HashMap<>(); + for (String subjectId : ids) { + long count = VersionedLogEntryHelper.countBySubjectId(collection, subjectId); + countMap.put(subjectId, count); + } + + // invoke callback + callback.showStat(new BlameStat(countMap)); + } catch (MongoClientException exception) { + logger.severe("Failed when querying the database: " + exception + + ". Failed to get statistics."); + callback.showStat(null); + } + } + }).start(); + } + + public static class BlameStat { + private final Map countMap; + + public BlameStat(Map countMap) { + this.countMap = countMap; + } + + public Map getCountMap() { + return Collections.unmodifiableMap(countMap); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BlameStat blameStat = (BlameStat) o; + return Objects.equals(countMap, blameStat.countMap); + } + + @Override + public int hashCode() { + return Objects.hash(countMap); + } + } + + public interface ShowStatCallback { + void showStat(@Nullable BlameStat stat); + } + +} diff --git a/src/main/java/com/keuin/blame/data/helper/VersionedLogEntryHelper.java b/src/main/java/com/keuin/blame/data/helper/VersionedLogEntryHelper.java new file mode 100644 index 0000000..064ae87 --- /dev/null +++ b/src/main/java/com/keuin/blame/data/helper/VersionedLogEntryHelper.java @@ -0,0 +1,22 @@ +package com.keuin.blame.data.helper; + +import com.keuin.blame.data.entry.LogEntry; +import com.keuin.blame.data.entry.LogEntryNames; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.model.Filters; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class VersionedLogEntryHelper { + public static Collection getLoggedSubjectsId(MongoCollection collection) { + List list = new ArrayList<>(); + for (String s : collection.distinct(LogEntryNames.SUBJECT_ID, String.class)) + list.add(s); + return list; + } + public static long countBySubjectId(MongoCollection collection, String subjectId) { + return collection.countDocuments(Filters.eq(LogEntryNames.SUBJECT_ID, subjectId)); + } +} -- cgit v1.2.3